<template>
  <div>
    <div id="ui_top_panel" class="top_panel">
      <!-- 导航栏 -->
      <div class="toolbar" style="margin-left: 50px">
        <ul>
          <li>
            <toggle-button
              v-model="isVetical"
              :width="60"
              :height="30"
              :disabled="image_info_list.length===0"
              :sync="true"
              :labels="{checked: '纵向', unchecked: '横向'}"
              @change="changeVetical"
            />
          </li>
          <li id="toolbar_zoom_out" style="margin-left: 2em;" title="缩小" @click="zoom_out()">&minus;</li>
          <li id="toolbar_zoom_in" title="放大" @click="zoom_in()">&plus;</li>
          <!-- <li id="toolbar_zoom_reset" @click="reset_zoom_level()" title="重置视图">&equals;</li> -->
          <li>
            <el-input-number v-model="num_degree" @change="handleDegreeChange" :precision="1"
                             :step="0.5" :min="-89" :max="89" label="旋转角" step-strictly
                             size="small" :disabled="!can_change_degree"
                             @focus="focusChangeDegreeInput" @blur="unfocusChangeDegreeInput">
            </el-input-number>
          </li>
          <li id="reposition" title="图片复位" @click="reposition()">复位</li>
          <li id="now_status" title="目前状态" style="margin-left: 20px">目前状态 ： <b>{{now_status}}</b></li>
          <li id="save_temp_data" title="暂存修改" style="margin-left: 40px" @click="complete_mark(0)">识别修改内容</li>
          <li id="save_data" title="确认修改" style="margin-left: 20px"  @click="complete_mark(1)">确认本次修改</li>
          <li id="see_data" title="查看修改" style="margin-left: 20px"  @click="seeEdit()">查看修改后识别结果</li>
          <li id="go_back" title="返回" style="margin-left: 20px"  @click="goBack()">返回</li>
        </ul>
      </div>
<!--      <input id="invisible_file_input" type="file" multiple name="files[]" style="display:none">-->
    </div>
    <!-- 中部：包括左侧工具栏和图像显示区 左边框250 -->
    <div class="middle_panel">
      <div id="leftsidebar" class="leftSizeBar" style="height: 100%;">
        <div>
          <el-card class="cardClass">
            <div>
              <div slot="header" class="clearfix">
                <span>图片名字:</span>
              </div>
              <div class="box">
                <div v-for="(img, index) in image_info_list" :key="index" @click="show_image(index)">
                  <el-button type="text" :class="{active: currentIndex === index}" style="padding:0;"
                             :title="img.name.imageName">
                    {{ img.name.imageName }}
                  </el-button>
                </div>
              </div>
            </div>
          </el-card>
        </div>
        <div id="leftAll" style="height: 100%" @contextmenu.prevent="onContextmenu0">
          <el-card class="box-card">
            <div id="leftTree" slot="header" style="height: 100%" class="clearfix">
              <span>目录树</span>
            </div>
            <div id="Tree" ref="treeRef" class="tree_box">
              <el-tree
                id="Tree1"
                ref="vuetree"
                :data="node_data"
                node-key="id"
                highlight-current
                default-expand-all
                :expand-on-click-node="false"
              >
                <!--@contextmenu 右键-->
                <span
                  slot-scope="{ node, data }"
                  style="width: 100%"
                  class="custom-tree-node"
                  @contextmenu.stop.prevent="onContextmenu($event,node,data)"
                  @click="() => show_node(node, data)"
                >
                  <span :style="getDetectStyle(node.data.need_detect)">
                    {{ node.label }} {{ node.data.label_idx }}
                  </span>
                </span>
              </el-tree>
            </div>
          </el-card>
        </div>
      </div> <!-- end of leftsidebar -->
      <!-- 主显示区：图像画布canvas -->
      <!--      <div id = "leftSidearHidden" display:none></div>-->
      <div id="display_area" v-loading="is_loading_current_image">
        <div id="canvas_panel" @mousewheel.prevent="handleWheel">
          <VueDragResize
            ref="vueDR"
            :is-resizable="false"
            :is-draggable="isDragActive&&image_info_list.length!==0"
            :w="1"
            :h="1"
            @dragging="onDragging"
          >
            <canvas id="image_canvas" class="mainSizeBar" :style="{cursor: 'pointer'}"/>
            <canvas id="region_canvas" class="mainSizeBar" :style="getStyle()"/>
          </VueDragResize>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import VueDragResize from 'vue-drag-resize' // vue拖拽缩放组件
// import {getImage, saveMarkDataRepate} from '../../service/commonService'
import {getImage, saveMarkDataRepate, getNowStatus} from '../../service/common'


class ImageMetadata {
  constructor(fileref, filename, size, fileid, filestatus) {
    this.fileid = fileid  //图片在数据库中的id
    this.filename = filename
    this.filestatus = filestatus
    this.size = size
    this.isVetical = true
    this.fileref = fileref // image url or local file ref.图片的详细信息
    this.regions = [] // 区域
    this.base64_img_data = '' // image data stored as base 64
    this.node_tree = [] // 目录树
  }
}

class ImageRegion {
  constructor() {
    this.node_id = 0 // 记录其在目录树节点的id
    this.is_user_selected = false // 默认为不选中
    this.shape_attributes = new Map() // 存该区域的坐标
  }
}

export default {
  name: 'Marking',
  components: {
    VueDragResize,
  },
  data() {
    return {
      now_status: "请求中...",
      second_json_is_exist: false,
      is_see_second:0,
      ocrWords: [],   // 识别好的并经过段落重组的文字
      resultPath: '',  //二次修改后回传的位置
      imageData: {},  // 二次识别的图片信息
      editNodeData: {}, //暂存修改的节点信息


      seletedImage: {},
      seletedFileList: [],  //图片列表
      /*
        filepath: "/home/data/newspaper/jpg/000984.jpg"  文件路径
        key: "266"    图片ID
        name: "000984.jpg"    图片名称
        result_path: ""   json路径
        status: 1   图片状态
        type: "image"   类型
      */
      img_metadata: {}, // 用来存已导入的每张图片的详细信息，包括上面标注的区域信息data structure to store loaded images metadata

      currentIndex: -1, // 当前鼠标点击的位置
      image_info_list: [], //图片列表         {id,name:{imageName,status},path}
      image_id: '', // 当前图片id
      image_id_list: [], // 保存已加载图片的id
      image_name_list: [], // 保存已加载图片的image_name
      image_path_list: [],
      image_index: -1, // 当前正在浏览的图片索引index

      hasClickSubmit: false,  //确认上传/删除对话框是否点击了上传或者暂存
      focusOnDegreeInput: false,
      num_degree: 0,  //当前框的旋转角
      can_change_degree: false,
      current_label: '',
      current_need_detect: 1,
      hasModified: false, //是否修改过当前标注
      is_can_upload: false,
      submitIndex: -1,
      index: 0,

      leftTree: '',
      leftAll: '',
      tree: '',

      isDragActive: false,
      selectpath: '/home/fzuir/newspaper_data',

      currentPath: '',

      isVetical: true,
      nid: 0, // 目录树的id
      node_data: [], // 目录树的json文件
      // current_node: {},
      current_parent_node: {},
      can_draw_region: false, // 是否能画图
      REGION_SHAPE: { // 标注区域的形状
        RECT: 'rect' // 矩形
      },
      REGION_EDGE_TOL: 5, // pixel，误差范围之内就算点击到框边缘
      REGION_CONTROL_POINT_SIZE: 2,
      REGION_POINT_RADIUS: 3,
      POLYGON_VERTEX_MATCH_TOL: 5,
      REGION_MIN_DIM: 3, // 如果画的框太小
      MOUSE_CLICK_TOL: 2, // 移动超过2px就算移动
      CANVAS_DEFAULT_ZOOM_LEVEL_INDEX: 3, // 指代1
      CANVAS_ZOOM_LEVELS: [0.25, 0.5, 0.75, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.5, 4, 4.5, 5], // 缩放的尺度

      THEME_REGION_BOUNDARY_WIDTH: 2,
      THEME_BOUNDARY_LINE_COLOR: '#1a1a1a',
      THEME_BOUNDARY_FILL_COLOR: '#ff0000',  //边框颜色
      THEME_SEL_REGION_FILL_COLOR: '#a2a8a2', //选中时颜色
      THEME_SEL_REGION_FILL_BOUNDARY_COLOR: '#000000', // 选中时边框颜色
      THEME_SEL_REGION_OPACITY: 0.5,  // 选中时透明度
      THEME_CONTROL_POINT_COLOR: '#ff0000',   // 选中时点的颜色

      canvas_regions: [], // 当前图片窗口中canvas的坐标 image regions spec. in canvas space
      canvas_scale: 1.0, // 原图缩小到canvas的倍数 current scale of canvas image

      current_image_filename: '',
      current_image: '',
      current_image_width: 0,
      current_image_height: 0,

      // image canvas
      img_canvas: '',
      img_ctx: '',
      reg_canvas: '',
      reg_ctx: '',
      canvas_width: 0,
      canvas_height: 0,

      // canvas zoom
      canvas_zoom_level_index: 3, // 1.0
      canvas_scale_without_zoom: 1.0,

      // state of the application
      is_user_drawing_region: false,
      current_image_loaded: false, // 图片是否在加载中
      is_window_resized: false,
      is_user_resizing_region: false,
      is_user_moving_region: false,
      is_user_drawing_polygon: false,
      is_region_selected: false,
      is_all_region_selected: false,
      is_user_updating_attribute_name: false,
      is_user_updating_attribute_value: false,
      is_user_adding_attribute_name: false,
      is_canvas_zoomed: false,
      is_loading_current_image: false, // 是否正在加载图片(导入图片的时候会用)
      is_region_boundary_visible: true,

      // region
      current_shape: '',
      user_sel_region_id: -1,
      click_x0: 0,
      click_y0: 0,
      click_x1: 0,
      click_y1: 0,
      region_click_x: 0,
      region_click_y: 0,
      region_edge: [-1, -1],
      current_x: 0,
      current_y: 0,

      // UI html elements
      ui_top_panel: '',
      canvas_panel: '',

      BBOX_LINE_WIDTH: 4,
      BBOX_SELECTED_OPACITY: 0.3,
      BBOX_BOUNDARY_FILL_COLOR_ANNOTATED: '#f2f2f2',
      BBOX_BOUNDARY_FILL_COLOR_NEW: '#aaeeff',
      BBOX_BOUNDARY_LINE_COLOR: '#1a1a1a',
      BBOX_SELECTED_FILL_COLOR: '#ffffff',

      is_ctrl_pressed: false,
      remote_node_data: [], // 从后端获取的当前图片的node_data
      complete_node_data: [],
      edit_node_data: [],
      remote_is_vetical: true, // 从后端获取的当前图片的状态
      remote_regions: [], // 远程node中读出的region
      max_id: 0, // 当前图片远程目录树node的最大id
      isDrawOther: false,
      current_other_node_id: 0,
    }
  },
  created() {
    // 在页面加载时读取sessionStorage里的状态信息
    if (sessionStorage.getItem('store')) {
      this.$store.replaceState(
        Object.assign(
          {},
          this.$store.state,
          JSON.parse(sessionStorage.getItem('store'))
        )
      )
    }

    // 在页面刷新时将vuex里的信息保存到sessionStorage里
    // beforeunload事件在页面刷新时先触发
    window.addEventListener('beforeunload', () => {
      sessionStorage.setItem('store', JSON.stringify(this.$store.state))
    })
  },
  activated() {
    console.log('activated')
    // 监听鼠标按下与松开
    window.addEventListener('keyup', this.keyup)
    window.addEventListener('keydown', this.keydown)
    this.getCheckedImage()
    this.show_image(0,0)
  },
  mounted() {
    this.get_init()
    this.reg_canvas.addEventListener('mousedown', this.mouse_down)
    this.reg_canvas.addEventListener('mouseup', this.mouse_up)
    this.reg_canvas.addEventListener('mousemove', this.mouse_move)
    this.reg_canvas.addEventListener('mouseover', this.mouse_over)
    // 定时获取当前状态
    this.timer = setInterval(this.refresh,10000)
  },
  deactivated() {
    console.log('deactivated')
    window.removeEventListener('keydown', this.keydown)
    this.image_info_list = []
    this.seletedImage = {}
    this.seletedFileList = []
    this.img_metadata = {}
    this.node_data = []
  },
  beforeDestroy() {
    console.log('beforeDestroy')
    window.removeEventListener('keydown', this.keydown)
  },
  methods: {
    // 定时获取当前状态
    refresh () {
      console.log('now_status --- refresh')
      getNowStatus(this.imageData['taskId'], this.imageData['image_id']).then(res => {
        this.now_status = res
      })
    },
    compare(obj1, obj2) {
      let s1 = obj1.status
      let s2 = obj2.status
      if (s1 < s2) return -1
      else if (s1 > s2) return 1
      else return 0
    },
    //完成标注
    finish_mark(){
      console.log("完成标注")
    },
    // 确认修改，回填json
    save_json(){
      console.log("确认修改，回填json")
    },
    //获得该任务中的所有图片
    getCheckedImage() {
      this.onDragging({top: 0, left: 0})
      // this.imageData = this.$route.query.imageData
      this.imageData = this.$store.state.imageDetail
      let imagePath = this.imageData['imagePath']
      let imageName = imagePath.split('/')[imagePath.split('/').length-1]   // 图片名字
      getNowStatus(this.imageData['taskId'], this.imageData['image_id']).then(res => {
        this.now_status = res
      })

      const data_item = {}
      data_item['key'] = this.imageData['taskId']
      data_item['name'] = imageName
      data_item['filepath'] = this.imageData['imagePath']
      // data_item['filepath'] = "/home/data/newspaper/jpg/000984.jpg"
      data_item['status'] = 3
      data_item['type'] = 'image'

      /*因为是标注，此时不拿json文件*/
      data_item['result_path'] = ''

      this.seletedFileList.push(data_item)
      this.store_remote_img_ref()
    },
    // 给所有已识别的节点加上isOcr = true 的属性
    // add_node_data_isocr(node){
    //   for(let i=0;i<node.length;i++){
    //     node[i]['isOcr'] = true
    //     if(node[i].children.length > 0){
    //       this.add_node_data_isocr(node[i].children)
    //     }
    //   }
    // },
    keydown(e) {
      if (e.which === 46 || e.which === 8) { // Del or Backspace
        if (!this.focusOnDegreeInput) {
          console.log('按下del，删除框')
          this.del_sel_regions()
          e.preventDefault() // 阻止默认事件，因为会导致搜索框不能删除文字，所以不阻止删除的冒泡时间
          return
        }
      }
      if (e.which === 37) { // 左移框
        if (this.is_region_selected) {
          console.log('左移3px', this.user_sel_region_id)
          this.key_move(-3, 0)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }
      if (e.which === 38) { // 上移框
        if (this.is_region_selected) {
          console.log('上移3px', this.user_sel_region_id)
          this.key_move(0, -3)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }
      if (e.which === 39) { // 右移框
        if (this.is_region_selected) {
          console.log('右移3px', this.user_sel_region_id)
          this.key_move(3, 0)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }
      if (e.which === 40) { // 上移框
        if (this.is_region_selected) {
          console.log('下移3px', this.user_sel_region_id)
          this.key_move(0, 3)
          this.reg_canvas.focus()
          e.preventDefault()
          return
        }
      }

      // Ctrl + 快捷键
      if (e.ctrlKey) {
        if (e.which === 83) { // Ctrl + s
          e.preventDefault()
          this.save_data(1)
        }
        this.is_ctrl_pressed = true
        this.isDragActive = true
        this.reg_canvas.style.cursor = 'pointer'
        this.reg_canvas.removeEventListener('mousedown', this.mouse_down)
        this.reg_canvas.removeEventListener('mouseup', this.mouse_up)
        this.reg_canvas.removeEventListener('mousemove', this.mouse_move)
        this.reg_canvas.removeEventListener('mouseover', this.mouse_over)
      }
    },
    keyup(e) {
      if (e.which === 17) {
        this.isDragActive = false
        this.is_ctrl_pressed = false
        this.reg_canvas.style.cursor = 'default'
        this.reg_canvas.addEventListener('mousedown', this.mouse_down)
        this.reg_canvas.addEventListener('mouseup', this.mouse_up)
        this.reg_canvas.addEventListener('mousemove', this.mouse_move)
        this.reg_canvas.addEventListener('mouseover', this.mouse_over)
      }
    },
    //复位
    reposition() {
      this.reset_zoom_level()
      this.onDragging({top: 0, left: 0})
    },
    onDragging(newRect) {
      this.$refs.vueDR.top = newRect.top
      this.$refs.vueDR.left = newRect.left
    },
    throttle(fn, gapTime) {
      const _this = this
      return function () {
        const _nowTime = +new Date()
        if (_nowTime - _this._lastTime > gapTime || !_this._lastTime) {
          fn(...arguments)// 函数可以带参数
          _this._lastTime = _nowTime
        }
      }
    },
    handleWheel(e) {
      e.stopPropagation()
      this.throttle(this.pageUpOrDown, 100)(e)
    },
    pageUpOrDown(e) {
      if (e.deltaY > 0) {
        // 向下
        // this.clickNext()//执行的事件逻辑。比如向下翻页
        this.zoom_out()
      } else if (e.deltaY < 0) {
        // 向上
        this.zoom_in()// 比如向上翻页
      }
    },
    getStyle() {
      if (this.isDragActive && this.image_info_list.length !== 0) {
        return {cursor: 'pointer'}
      } else {
        return {}
      }
    },
    getDetectStyle(need_detect) {
      if (need_detect === 0) return {width: '100%', color: 'blue'}
      else return {width: '100%'}
    },
    handleDegreeChange(value) {
      console.log('旋转角', value)
      const current_region = this.img_metadata[this.image_id].regions[this.user_sel_region_id]//用户选择的区域
      let image_attr = current_region.shape_attributes //真实的坐标
      let canvas_attr = this.canvas_regions[this.user_sel_region_id].shape_attributes //在canvas中的坐标
      let current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)//当前选择区域的目录树node信息
      // console.log('当前区域对应的目录树节点的信息：', current_node_info)
      switch (canvas_attr.get('name')) {
        case this.REGION_SHAPE.RECT:
          image_attr.set('degree', value)
          canvas_attr.set('degree', value)
          current_node_info.data.degree = value
          this.hasModified = true
          this.redraw_reg_canvas()
          this.reg_canvas.focus()
          break
      }
    },
    /*
    初始化
    * */
    focusChangeDegreeInput() {
      console.log('输入框获取焦点')
      this.focusOnDegreeInput = true
    },
    unfocusChangeDegreeInput() {
      console.log('输入框失去焦点')
      this.focusOnDegreeInput = false
    },
    get_init() {
      // this.invisible_file_input = document.getElementById('invisible_file_input')
      this.img_canvas = document.getElementById('image_canvas')
      this.img_ctx = this.img_canvas.getContext('2d')
      this.reg_canvas = document.getElementById('region_canvas')
      this.leftAll = document.getElementById('leftAll')
      this.leftTree = document.getElementById('leftTree')
      this.tree = document.getElementById('Tree')
      this.reg_ctx = this.reg_canvas.getContext('2d')
      this.ui_top_panel = document.getElementById('ui_top_panel')
      this.canvas_panel = document.getElementById('canvas_panel') // 包裹image_canvas和region_canvas的区域
      this.canvas_zoom_level_index = this.CANVAS_DEFAULT_ZOOM_LEVEL_INDEX
      this.current_shape = this.REGION_SHAPE.RECT
    },
    /*
    目录树部分
    * */
    show_node(node, data) {
      console.log('点击节点')
      console.log('node', node)  //level只是层级 1-3 parent是父节点
      console.log('data', data)
      let current_node_id = node.data.id
      let children_ids = []
      this.find_children_id(data, children_ids)
      this.toggle_all_regions_selection(false)
      for (let j = 0; j < children_ids.length; j++) {
        for (let i = 0; i < this.canvas_regions.length; i++) {
          if (this.canvas_regions[i].node_id === children_ids[j]) {
            // console.log('找到对应的区域', this.canvas_regions[i])
            this.set_region_select_state(i, true)
            break
          }
        }
      }
      this.redraw_reg_canvas()
      this.reg_canvas.focus()
    },
    find_children_id(parent_node, children_ids) {
      children_ids.push(parent_node.id)
      for (let i = 0; i < parent_node.children.length; i++) {
        this.find_children_id(parent_node.children[i], children_ids)
      }
    },
    // 添加一级节点到node_data
    addPush(msg) {
      this.node_data.push(msg)
      this.hasModified = true
      setTimeout(() => {
        this.$refs.treeRef.scrollTop = this.$refs.treeRef.scrollHeight
      }, 100)
    },
    /**
     * 目录树右键菜单
     */
    // 点击目录树card
    onContextmenu0(event,node) {
      // 如果没导入图片，则返回
      if (this.image_info_list.length === 0) {
        return
      }
      this.$contextmenu({
        items: [{
          label: "添加新闻",
          onClick: () => {
            let num_label = this.count_label_num1(this.node_data, '新闻')
            let new_news = {
              id: this.nid++,
              label: '新闻',
              label_idx: num_label + 1,
              need_detect: 1,
              degree: 0,
              xy: [],
              children: []
            }
            this.addPush(new_news)
          }
        }, {
          label: "添加报头",
          onClick: () => {
            // console.log("添加报头"); //添加报头和添加普通节点不一样，普通节点可以获取到parent的node信息
            let num_label = this.count_label_num1(this.node_data, '报头')
            let new_newspaperTitle = {
              id: this.nid++,
              label: '报头',
              label_idx: num_label + 1,
              need_detect: 1,
              degree: 0,
              xy: [],
              children: []
            }
            this.addPush(new_newspaperTitle)
            // this.node_data.push(new_newspaperTitle)  //往目录树添加节点
          }
        }, {
          label: "添加广告",
          onClick: () => {
            // console.log("添加广告");
            let num_label = this.count_label_num1(this.node_data, '广告')
            let new_ads = {
              id: this.nid++,
              label: '广告',
              label_idx: num_label + 1,
              need_detect: 1,
              degree: 0,
              xy: [],
              children: []
            }
            this.addPush(new_ads)
            // this.node_data.push(new_ads)  //往目录树添加节点
          }
        },
        //   {
        //   label: "添加其他",
        //   onClick: () => {
        //     let num_label = this.count_label_num1(this.node_data, '其他')
        //     let new_others = {
        //       id: this.nid++,
        //       label: '其他',
        //       label_idx: num_label + 1,
        //       need_detect: 1,
        //       degree: 0,
        //       xy: [],
        //       children: []
        //     }
        //     this.addPush(new_others)
        //     setTimeout(()=>{
        //       this.current_parent_node = this.$refs['vuetree'].getNode(new_others.id).parent
        //       this.current_other_node_id = new_others.id
        //       this.isDrawOther = true
        //       console.log('this.current_parent_node', this.current_parent_node)
        //       this.current_label = '其他'
        //       this.current_need_detect = 1
        //       this.can_draw_region = true }, 200)
        //   }
        // }
      ],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    // 在节点上右键
    onContextmenu(event, node, data) { // 点击目录树node
      // console.log("右键了")
      // node为当前节点，data为标注框
      if (this.image_info_list.length === 0) { // 如果没导入图片，则
        return
      }
      if (node.data.label === '新闻') {
        // console.log('点击新闻，可以添加标题、作者、时间')
        this.onContextmenu_news(event, node, data)
      } else if (node.data.label === '报头') {
        // console.log('点击报头，可以添加包头部分的东西')
        this.onContextmenu_newspaperTitle(event, node, data)
      } else if (node.data.label === '广告') {
        // console.log('点击广告，可以添加内容和图片')
        this.onContextmenu_ads(event, node, data)
      } else if (node.data.label === '其他') {
        // console.log('点击其他，可以添加正文')
        this.onContextmenu_title(event, node, data)
      } else if (node.data.label === '标题' || node.data.label === '分标题') {
        // console.log('点击标题，可以添加副标题、正文')
        this.onContextmenu_title(event, node, data)
      } else {
        // console.log('点击到除了标题和新闻以外的节点，只有删除的选项')
        this.onContextmenu_other(event, node, data)
      }
    },
    // 目录树 新闻
    onContextmenu_news(event, node, data) {
      console.log("添加二级节点")
      this.$contextmenu({
        items: [
          // {
          //   label: '添加二次标注',
          //   onClick: () => {
          //     this.add_node(node, '二次标注')
          //   }
          // },
          {
          label: '添加标题',
          onClick: () => {
            // console.log("添加标题");
            this.add_node(node, '标题')
          }
        }
        , {
          label: '添加分标题',
          onClick: () => {
            // console.log("添加标题");
            this.add_node(node, '分标题')
          }
        }, {
          label: '添加作者',
          onClick: () => {
            // console.log("添加作者");
            this.add_node(node, '作者')
          }
        }, {
          label: '添加时间',
          onClick: () => {
            // console.log("添加时间");
            this.add_node(node, '时间')
          }
        }, {
          label: '添加图片',
          onClick: () => {
            // console.log("添加图片");
            this.add_node(node, '图片')
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
      // 新闻 添加标题
      onContextmenu_title(event, node, data) {
        let detect_label = '不识别该区域'
        if (node.data.need_detect === 0) {
          detect_label = '识别该区域'
        }
        this.$contextmenu({
          items: [
          //   {
          //   label: '添加副标题',
          //   onClick: () => {
          //     // console.log("添加副标题");
          //     this.add_node(node, '副标题')
          //   }
          // },
          //   {
          //     label: '添加二次标注',
          //     onClick: () => {
          //       // console.log("添加标题");
          //       this.add_node(node, '二次标注')
          //     }
          //   },
            {
            label: '添加正文',
            onClick: () => {
              // console.log("添加正文");
              this.add_node(node, '正文')
            }
          }, {
            label: detect_label,
            onClick: () => {
              // console.log(detect_label);
              if (node.data.need_detect === 0) {
                node.data.need_detect = 1 // 不识别该区域
              } else {
                node.data.need_detect = 0 // 不识别该区域
              }
            }
          }, {
            label: '删除节点',
            onClick: () => {
              // console.log("删除节点");
              this.remove_nodes(node, data)
            }
          }],
          event,
          customClass: 'custom-class',
          zIndex: 3,
          minWidth: 180
        })
        event.preventDefault()
      },
      // 点击到除了标题、分标题和新闻以外的节点，只有删除的选项
      onContextmenu_other(event, node, data) {
        let detect_label = '不识别该区域'
        if (node.data.need_detect === 0) {
          detect_label = '识别该区域'
        }
        this.$contextmenu({
          items: [
            // {
            //   label: '添加二次标注',
            //   onClick: () => {
            //     // console.log("添加标题");
            //     this.add_node(node, '二次标注')
            //   }
            // },
            {
            label: detect_label,
            onClick: () => {
              // console.log(detect_label);
              if (node.data.need_detect === 0) {
                node.data.need_detect = 1 // 不识别该区域
              } else {
                node.data.need_detect = 0 // 不识别该区域
              }
            }
          }, {
            label: '删除节点',
            onClick: () => {
              // console.log("删除节点");
              this.remove_nodes(node, data)
            }
          }],
          event,
          customClass: 'custom-class',
          zIndex: 3,
          minWidth: 180
        })
        event.preventDefault()
      },
    // 目录 报头
    onContextmenu_newspaperTitle(event, node, data) {
      this.$contextmenu({
        items: [
          // {
          //   label: '添加二次标注',
          //   onClick: () => {
          //     // console.log("添加标题");
          //     this.add_node(node, '二次标注')
          //   }
          // },
          {
          label: '添加报纸名称',
          onClick: () => {
            // console.log("添加报纸名称");
            this.add_node(node, '报纸名称')
          }
        }, {
          label: '添加报纸日期',
          onClick: () => {
            // console.log("添加报纸日期");
            this.add_node(node, '报纸日期')
          }
        }, {
          label: '添加报纸星期',
          onClick: () => {
            // console.log("添加报纸星期");
            this.add_node(node, '报纸星期')
          }
        }, {
          label: '添加报纸版次',
          onClick: () => {
            // console.log("添加报纸版次");
            this.add_node(node, '报纸版次')
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    // 目录 广告
    onContextmenu_ads(event, node, data) {
      this.$contextmenu({
        items: [
          // {
          //   label: '添加二次标注',
          //   onClick: () => {
          //     // console.log("添加标题");
          //     this.add_node(node, '二次标注')
          //   }
          // },
          {
          label: '添加广告内容',
          onClick: () => {
            // console.log("添加广告内容");
            this.add_node(node, '广告内容')
          }
        }, {
          label: '添加图片',
          onClick: () => {
            // console.log("添加图片");
            this.add_node(node, '图片')
          }
        }, {
          label: '删除节点',
          onClick: () => {
            // console.log("删除节点");
            this.remove_nodes(node, data)
          }
        }],
        event,
        customClass: 'custom-class',
        zIndex: 3,
        minWidth: 180
      })
      event.preventDefault()
    },
    // 添加节点
    add_node(node, label) {
      // console.log("这里是添加节点")
      // node为当前父节点
      this.current_label = label
      if (label === '图片') {   // 图片不用识别
        this.current_need_detect = 0
      } else {
        this.current_need_detect = 1
        // this.current_node = {id: this.nid++, label: label, need_detect: 1, xy: [], children: []}
      }
      this.can_draw_region = true //可以画框
      this.current_parent_node = node // 父节点
      // console.log("this.current_parent_node",this.current_parent_node)
    },
    //删除该节点的目录树信息
    remove_node(node, data) {
      const parent = node.parent
      const children = parent.data.children || parent.data
      const index = children.findIndex(d => d.id === data.id)
      children.splice(index, 1)
      setTimeout(() => {
        this.order_label_idx(parent, data.label)
      }, 100)
    },
    //删除其该节点以及子节点的区域和目录树信息
    remove_nodes(node, data) {
      this.can_draw_region = false
      this.do_remove_nodes(node, data)
      this.is_all_region_selected = false
      this.is_region_selected = false
      this.user_sel_region_id = -1
      if (this.canvas_regions.length === 0) {
        this.clear_reg_canvas()
      } else {
        this.redraw_reg_canvas()
      }
      this.reg_canvas.focus()
    },
    //删除自身region 红框
    do_remove_nodes(node, data) {
      for (let i = 0; i < this.canvas_regions.length; i++) { //删除区域
        if (this.canvas_regions[i].node_id === data.id) {
          this.canvas_regions.splice(i, 1)
          this.img_metadata[this.image_id].regions.splice(i, 1)
          break
        }
      }
      //删除子节点的region和node_data
      for (let i = 0; i < node.childNodes.length; i++) {
        this.do_remove_nodes(node.childNodes[i], node.childNodes[i].data)
      }
      //删除自身node_data信息
      this.remove_node(node, data)
    },

    get_image_id(filename, size) {
      if (typeof (size) === 'undefined') {
        return filename
      } else {
        return filename + size
      }
    },
    set_all_canvas_scale(s) {
      this.img_ctx.scale(s, s) // 只缩放以后的画图操作，会同时缩放坐标
      this.reg_ctx.scale(s, s)
    },
    set_all_canvas_size(w, h) {
      this.img_canvas.height = h
      this.img_canvas.width = w
      this.reg_canvas.height = h
      this.reg_canvas.width = w
      this.canvas_panel.style.height = h + 'px'
      this.canvas_panel.style.width = w + 'px'
    },
    //计算同名标签一级节点的label数量
    count_label_num1(parent_node_data, label) {
      console.log("添加一级标签")
      // parent_node_data 为所有父节点  label为添加的标签名字
      let num = 0
      for (let i = 0; i < parent_node_data.length; i++) {
        if (parent_node_data[i].label === label) {
          num++
        }
      }
      return num
    },
    count_label_num(parent_node_data, label) {  //计算二三级节点的label数量
      let num = 0
      for (let i = 0; i < parent_node_data.children.length; i++) {
        if (parent_node_data.children[i].label === label) {
          num++
        }
      }
      return num
    },
    order_label_idx(parent_node, label) {
      let idx = 1
      for (let i = 0; i < parent_node.childNodes.length; i++) {
        if (parent_node.childNodes[i].data.label === label) {
          // console.log(idx)
          parent_node.childNodes[i].data.label_idx = idx
          idx++
        }
      }
    },
    // transform regions in image space to canvas space'
    // 将图像空间中的区域变换到画布空间
    load_canvas_regions() {
      // load all existing annotations into canvas_regions
      const regions = this.img_metadata[this.image_id].regions
      // console.log('当前选择的图片id：', this.image_id)
      this.canvas_regions = []
      for (let i = 0; i < regions.length; ++i) {
        const regioni = new ImageRegion()
        regioni.node_id = regions[i].node_id
        for (const key of regions[i].shape_attributes.keys()) { // img_metadata.regions存着该图片各个框的坐标信息
          const value = regions[i].shape_attributes.get(key)
          regioni.shape_attributes.set(key, value)
        }
        this.canvas_regions.push(regioni)
        switch (this.canvas_regions[i].shape_attributes.get('name')) {
          case this.REGION_SHAPE.RECT:
            const x = regions[i].shape_attributes.get('x') / this.canvas_scale // 转化为画布大小
            const y = regions[i].shape_attributes.get('y') / this.canvas_scale
            const width = regions[i].shape_attributes.get('width') / this.canvas_scale
            const height = regions[i].shape_attributes.get('height') / this.canvas_scale
            this.canvas_regions[i].shape_attributes.set('x', Math.round(x))
            this.canvas_regions[i].shape_attributes.set('y', Math.round(y))
            this.canvas_regions[i].shape_attributes.set('width', Math.round(width))
            this.canvas_regions[i].shape_attributes.set('height', Math.round(height))
            break
        }
      }
    },
    // 画画
    redraw_reg_canvas() {
      if (this.current_image_loaded) {
        if (this.canvas_regions.length > 0) {
          // 清空矩形框的画布
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
          if (this.is_region_boundary_visible) {
            this.draw_all_regions()
          }
        }
      }
    },
    // 海杰 画出红框
    draw_all_regions() {
      for (let i = 0; i < this.canvas_regions.length; ++i) {
        const attr = this.canvas_regions[i].shape_attributes // canvas_regions存的是缩放过的
        // console.log("attr",attr.size)
        const is_selected = this.canvas_regions[i].is_user_selected
        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            this.draw_rect_region(attr.get('x'),
              attr.get('y'),
              attr.get('width'),
              attr.get('height'),
              attr.get('degree'),
              is_selected,
              attr.get('isOcr'))
            break
        }
      }
    },
    // 画出所有框
    draw_rect_region(x, y, w, h, degree, is_selected,isOcr) {
      if (is_selected) {
        let t = this.draw_rect(x, y, w, h, degree)
        let new_x = t.new_x  //转换后的新坐标
        let new_y = t.new_y
        this.reg_ctx.strokeStyle = this.THEME_SEL_REGION_FILL_BOUNDARY_COLOR
        this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH / 2
        this.reg_ctx.stroke() //绘制出通过 moveTo() 和 lineTo() 方法定义的路径
        this.reg_ctx.fillStyle = this.THEME_SEL_REGION_FILL_COLOR
        this.reg_ctx.globalAlpha = this.THEME_SEL_REGION_OPACITY //透明度
        this.reg_ctx.fill()
        this.reg_ctx.globalAlpha = 1.0  //不透明
        //画边角四个点
        this.draw_control_point(new_x[0], new_y[0])
        this.draw_control_point(new_x[1], new_y[1])
        this.draw_control_point(new_x[2], new_y[2])
        this.draw_control_point(new_x[3], new_y[3])
      } else {
        // 如果是已识别好的，边框颜色设为红色，若是再标注的，边框则为蓝色
        if(isOcr){
          this.reg_ctx.strokeStyle = this.THEME_BOUNDARY_FILL_COLOR     //边框颜色限定
        }else{
          this.reg_ctx.strokeStyle = 'blue'     //边框颜色限定
        }
        this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH
        // this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH / 2
        this.draw_rect(x, y, w, h, degree)
        this.reg_ctx.stroke()
      }
    },
    // control point for resize of region boundaries
    draw_control_point(cx, cy) {
      this.reg_ctx.beginPath()
      this.reg_ctx.arc(cx, cy, this.REGION_POINT_RADIUS, 0, 2 * Math.PI, false)
      this.reg_ctx.closePath()
      this.reg_ctx.fillStyle = this.THEME_CONTROL_POINT_COLOR
      this.reg_ctx.globalAlpha = 1.0
      this.reg_ctx.fill()
    },
    draw_rect(x, y, w, h, degree) {
      if (degree === 0) {
        this.reg_ctx.beginPath()
        this.reg_ctx.moveTo(x, y)
        this.reg_ctx.lineTo(x + w, y)
        this.reg_ctx.lineTo(x + w, y + h)
        this.reg_ctx.lineTo(x, y + h)
        this.reg_ctx.closePath()//闭环,从当前点到开始点的路径
        let new_x = [x, x + w, x + w, x]
        let new_y = [y, y, y + h, y + h]
        return {
          new_x: new_x,
          new_y: new_y
        }
      } else {
        let c_x = x + w / 2
        let c_y = y + h / 2
        let t = this.compulte_new_xy(x, y, w, h, degree, c_x, c_y)
        let new_x = t.new_x
        let new_y = t.new_y
        this.reg_ctx.beginPath()
        this.reg_ctx.moveTo(new_x[0], new_y[0])
        this.reg_ctx.lineTo(new_x[1], new_y[1])
        this.reg_ctx.lineTo(new_x[2], new_y[2])
        this.reg_ctx.lineTo(new_x[3], new_y[3])
        this.reg_ctx.closePath()//闭环,从当前点到开始点的路径
        return {
          new_x: new_x,
          new_y: new_y
        }
      }
    },
    compulte_new_xy(x, y, w, h, degree, c_x, c_y) {
      let old_x = [x, x + w, x + w, x]
      let old_y = [y, y, y + h, y + h]
      let new_x = []
      let new_y = []
      for (let i = 0; i < old_x.length; i++) {  //矩形四角绕中心点旋转degree度
        new_x.push(Math.round((old_x[i] - c_x) * Math.cos(degree * (Math.PI / 180)) - (old_y[i] - c_y) * Math.sin(degree * (Math.PI / 180)) + c_x))
        new_y.push(Math.round((old_x[i] - c_x) * Math.sin(degree * (Math.PI / 180)) + (old_y[i] - c_y) * Math.cos(degree * (Math.PI / 180)) + c_y))
      }
      return {
        new_x: new_x,
        new_y: new_y
      }
    },
    // 放大
    zoom_in() {
      if (!this.current_image_loaded) {
        // console.log('请先加载图片,First load some images!')
        return
      }
      if (this.canvas_zoom_level_index === (this.CANVAS_ZOOM_LEVELS.length - 1)) {
        // console.log('Further zoom-in not possible')
      } else {
        this.canvas_zoom_level_index += 1
        this.is_canvas_zoomed = true
        const zoom_scale = this.CANVAS_ZOOM_LEVELS[this.canvas_zoom_level_index]
        this.set_all_canvas_scale(zoom_scale)
        this.set_all_canvas_size(this.canvas_width * zoom_scale,
          this.canvas_height * zoom_scale)
        this.canvas_scale = this.canvas_scale_without_zoom / zoom_scale

        this.load_canvas_regions() // image to canvas space transform
        this.redraw_img_canvas()
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // console.log('Zoomed in to level ' + zoom_scale + 'X')
      }
    },
    // 缩小
    zoom_out() {
      if (!this.current_image_loaded) {
        // console.log('请先加载图片,First load some images!')
        return
      }
      if (this.canvas_zoom_level_index === 0) { // 不能再缩小了
        // console.log('Further zoom-out not possible')
      } else {
        this.canvas_zoom_level_index -= 1
        this.is_canvas_zoomed = true
        const zoom_scale = this.CANVAS_ZOOM_LEVELS[this.canvas_zoom_level_index]
        this.set_all_canvas_scale(zoom_scale)
        this.set_all_canvas_size(this.canvas_width * zoom_scale,
          this.canvas_height * zoom_scale) // 缩放画布，但是会把图片清空
        this.canvas_scale = this.canvas_scale_without_zoom / zoom_scale

        this.load_canvas_regions() // 加载当前图片的标注框image to canvas space transform
        this.redraw_img_canvas() // 画图片
        this.redraw_reg_canvas() // 画矩形框
        this.reg_canvas.focus()
        // console.log('Zoomed out to level ' + zoom_scale + 'X')
      }
    },
    reset_zoom_level() {
      if (!this.current_image_loaded) {
        // console.log('First load some images!')
        return
      }
      if (this.is_canvas_zoomed) {
        this.is_canvas_zoomed = false
        this.canvas_zoom_level_index = this.CANVAS_DEFAULT_ZOOM_LEVEL_INDEX
        const zoom_scale = this.CANVAS_ZOOM_LEVELS[this.canvas_zoom_level_index]
        this.set_all_canvas_scale(zoom_scale)
        this.set_all_canvas_size(this.canvas_width, this.canvas_height)
        this.canvas_scale = this.canvas_scale_without_zoom

        this.load_canvas_regions() // image to canvas space transform
        this.redraw_img_canvas()
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // console.log('Zoom reset')
      } else {
        // console.log('Cannot reset zoom because image zoom has not been applied!')
      }
    },
    redraw_img_canvas() {
      if (this.current_image_loaded) {
        this.img_ctx.clearRect(0, 0, this.img_canvas.width, this.img_canvas.height)
        this.img_ctx.drawImage(this.current_image, 0, 0,
          this.img_canvas.width, this.img_canvas.height)
      }
    },
    is_on_region_corner(px, py) {
      const region_edge = [-1, -1] // region_id, corner_id [top-left=1,top-right=2,bottom-right=3,bottom-left=4]
      for (let i = 0; i < this.canvas_regions.length; ++i) { // canvas_regions存着当前图片的框坐标，非原图尺度
        const attr = this.canvas_regions[i].shape_attributes
        let result = false
        region_edge[0] = i
        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            result = this.is_on_rect_edge(attr.get('x'),
              attr.get('y'),
              attr.get('width'),
              attr.get('height'),
              attr.get('degree'),
              px, py)
            break
        }
        if (result > 0) { // 电机在框i的边缘上
          region_edge[1] = result
          return region_edge
        }
      }
      region_edge[0] = -1
      return region_edge
    },
    is_on_rect_edge(x, y, w, h, degree, px, py) {
      if (degree === 0) {
        let dx0 = Math.abs(x - px)
        let dy0 = Math.abs(y - py)
        let dx1 = Math.abs(x + w - px)
        let dy1 = Math.abs(y + h - py)
        //[top-left=1,top-right=2,bottom-right=3,bottom-left=4]
        if (dx0 < this.REGION_EDGE_TOL &&
          dy0 < this.REGION_EDGE_TOL) {
          return 1
        }
        if (dx1 < this.REGION_EDGE_TOL &&
          dy0 < this.REGION_EDGE_TOL) {
          return 2
        }
        if (dx1 < this.REGION_EDGE_TOL &&
          dy1 < this.REGION_EDGE_TOL) {
          return 3
        }
        if (dx0 < this.REGION_EDGE_TOL &&
          dy1 < this.REGION_EDGE_TOL) {
          return 4
        }
        return 0
      } else {
        let c_x = x + w / 2
        let c_y = y + h / 2
        let t = this.compulte_new_xy(x, y, w, h, degree, c_x, c_y)
        let new_x = t.new_x
        let new_y = t.new_y
        for (let i = 0; i < new_x.length; i++) {
          let dx = Math.abs(new_x[i] - px)
          let dy = Math.abs(new_y[i] - py)
          if (dx < this.REGION_EDGE_TOL &&
            dy < this.REGION_EDGE_TOL) {
            return i + 1
          }
        }
        return 0
      }
    },
    is_inside_region(px, py, descending_order) {
      const N = this.canvas_regions.length
      if (N === 0) {
        return -1
      }
      let start, end, del
      // traverse the canvas regions in alternating ascending
      // and descending order to solve the issue of nested regions
      if (descending_order) {
        start = N - 1
        end = -1
        del = -1
      } else {
        start = 0
        end = N
        del = 1
      }

      let i = start
      while (i !== end) {
        const yes = this.is_inside_this_region(px, py, i)
        if (yes) {
          return i
        }
        i = i + del
      }
      return -1
    },
    is_inside_this_region(px, py, region_id) {
      const attr = this.canvas_regions[region_id].shape_attributes
      let result = false
      switch (attr.get('name')) {
        case this.REGION_SHAPE.RECT:
          result = this.is_inside_rect(attr.get('x'),
            attr.get('y'),
            attr.get('width'),
            attr.get('height'),
            attr.get('degree'),
            px, py)
          break
      }
      return result
    },
    is_inside_rect(x, y, w, h, degree, px, py) {
      if (degree === 0) {
        return px > x &&
          px < (x + w) &&
          py > y &&
          py < (y + h)
      } else {
        let c_x = x + w / 2  //旋转中心
        let c_y = y + h / 2
        let t = this.compulte_new_xy(x, y, w, h, degree, c_x, c_y)  //绕着矩形中心旋转degree度
        let all_points_x = t.new_x
        let all_points_y = t.new_y
        all_points_x.push(t.new_x[0])  //形成一个闭环
        all_points_y.push(t.new_y[0])
        let wn = 0;    // the  winding number counter
        // loop through all edges of the polygon
        for (let i = 0; i < all_points_x.length - 1; i++) {   // edge from V[i] to  V[i+1]
          let is_left_value = this.is_left(all_points_x[i], all_points_y[i],
            all_points_x[i + 1], all_points_y[i + 1],
            px, py);
          if (all_points_y[i] <= py) {
            if (all_points_y[i + 1] > py && is_left_value > 0) {  // 线是从下到上,点击点在线的左边
              ++wn;
            }
          } else {
            if (all_points_y[i + 1] <= py && is_left_value < 0) {  //线是从上到下,点击点在线的右边
              --wn;
            }
          }
        }
        return wn !== 0;
      }
    },
    // returns
    // >0 if (x2,y2) lies on the left side of line joining (x0,y0) and (x1,y1)
    // =0 if (x2,y2) lies on the line joining (x0,y0) and (x1,y1)
    // >0 if (x2,y2) lies on the right side of line joining (x0,y0) and (x1,y1)
    // source: http://geomalgorithms.com/a03-_inclusion.html
    is_left(x0, y0, x1, y1, x2, y2) {
      return (((x1 - x0) * (y2 - y0)) - ((x2 - x0) * (y1 - y0)));
    },
    toggle_all_regions_selection(is_selected) {
      for (let i = 0; i < this.canvas_regions.length; ++i) {
        this.canvas_regions[i].is_user_selected = is_selected // 当前图片的所有region都清空
        this.img_metadata[this.image_id].regions[i].is_user_selected = is_selected
      }
      this.is_all_region_selected = is_selected
    },
    rect_update_corner(corner_id, d, x, y) {
      // pre-condition : d[x0,y0,x1,y1] is standarized
      // post-condition : corner is moved ( d may not stay standarized )
      switch (corner_id) {
        case 1: // top-left
          d[0] = x
          d[1] = y
          break
        case 3: // bottom-right
          d[2] = x
          d[3] = y
          break
        case 2: // top-right
          d[2] = x
          d[1] = y
          break
        case 4: // bottom-left
          d[0] = x
          d[3] = y
          break
      }
    },
    rect_standarize_coordinates(d) {
      // d[x0,y0,x1,y1]
      // ensures that (d[0],d[1]) is top-left corner while
      // (d[2],d[3]) is bottom-right corner
      if (d[0] > d[2]) {
        // swap
        const t = d[0]
        d[0] = d[2]
        d[2] = t
      }

      if (d[1] > d[3]) {
        // swap
        const t = d[1]
        d[1] = d[3]
        d[3] = t
      }
    },
    set_region_select_state(region_id, is_selected) {
      this.canvas_regions[region_id].is_user_selected = is_selected
      this.img_metadata[this.image_id].regions[region_id].is_user_selected = is_selected
    },
    /**
     * 在画布上按del键，删除该node以及其children下所有的canvas_regions以及img_matedata中对应regions的信息
     */
    del_sel_regions() {
      if (!this.current_image_loaded) {
        // console.log('请加载图片!', this.current_image_loaded)
        // this.openMessageBox('请加载图片!')
        return
      }
      this.hasModified = true
      let del_region_count = 0
      if (this.is_all_region_selected) {
        del_region_count = this.canvas_regions.length
        this.canvas_regions.splice(0)
        this.img_metadata[this.image_id].regions.splice(0)
      } else {
        const sorted_sel_reg_id = []
        for (let i = 0; i < this.canvas_regions.length; ++i) {
          if (this.canvas_regions[i].is_user_selected) {
            sorted_sel_reg_id.push(i)
          }
        }
        sorted_sel_reg_id.sort(function (a, b) {
          return (b - a)
        })
        for (let i = 0; i < sorted_sel_reg_id.length; ++i) {
          // 由于删除的区域可能是处在第二级的标题或者作者，所以需要删除其节点children下的所有区域
          // remove_node会移除目录树上对应的节点，但是不会移除canvas_regions以及img_matedata中的region
          // 需要有对应的框id才可以删除他们
          const select_node_id = this.img_metadata[this.image_id].regions[sorted_sel_reg_id[i]].node_id
          // console.log('要删除的node_id:', select_node_id)
          const select_node = this.$refs['vuetree'].getNode(select_node_id)// 获取要删除的区域
          // console.log(select_node)
          this.del_node_children_region(select_node) // 在canvas_regions以及img_matedata中删除选中node的叶子结点区域
          // 删除自身在canvas和img_metadata上的节点
          this.canvas_regions.splice(sorted_sel_reg_id[i], 1)// 在canvas_regions中删除自己
          this.img_metadata[this.image_id].regions.splice(sorted_sel_reg_id[i], 1)
          // 删除自身及children在目录树中对应的节点
          this.remove_node(select_node, select_node.data)// 在目录树中删除对应的节点
          del_region_count += 1
        }
      }
      this.is_all_region_selected = false
      this.is_region_selected = false
      this.user_sel_region_id = -1
      if (this.canvas_regions.length === 0) {
        // all regions were deleted, hence clear region canvas
        this.clear_reg_canvas()
      } else {
        this.redraw_reg_canvas()
      }
      this.reg_canvas.focus()
      // console.log('Deleted ' + del_region_count + ' selected regions')
    },
    /**
     * 在画布上按del键，删除该node的children下所有的canvas_regions以及img_matedata中对应regions的信息
     */
    del_node_children_region(node) {
      if (node.childNodes.length === 0) { // 没有子节点
        // console.log('该树没有子节点')
      } else { // 从区域上选择只会删除二级节点
        const children_ids = []
        if (node.level === 2) { // 要删除的是标题
          for (let i = 0; i < node.childNodes.length; i++) {
            children_ids.push(node.childNodes[i].data.id)
          }
          // console.log('选择的是标题，子节点有:', children_ids)
        }
        for (let i = 0; i < children_ids.length; i++) {
          for (let j = 0; j < this.canvas_regions.length; j++) {
            if (this.canvas_regions[j].node_id === children_ids[i]) {
              this.canvas_regions.splice(j, 1) // canvas_region和img_metadata.regions上的东西都一致
              this.img_metadata[this.image_id].regions.splice(j, 1)
              break // 删除下一个children
            }
          }
        }
      }
    },
    clear_reg_canvas() {
      this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
    },
    openMessageBox(message) {
      this.$alert(message, ' ', {
        confirmButtonText: '确定'
        // callback: action => {
        //   this.$message({
        //     type: 'info',
        //     message: `action: ${ action }`
        //   });
        // }
      })
    },
    dragMove(folder, data) {
      // console.log(folder, data)
    },
    // 远程文件加载入图片列表中
    store_remote_img_ref() {
      const user_selected_images = this.seletedFileList // 该任务的文件信息
      for (let i = 0; i < user_selected_images.length; ++i) { // 遍历选好的图片
        const img_id = user_selected_images[i].key  //图片数据库的id,每张图片都有唯一的数据库id
        const filename = user_selected_images[i].name
        const filepath = user_selected_images[i].filepath
        const filestatus = user_selected_images[i].status
        const size = user_selected_images[i].size

        this.img_metadata[img_id] = new ImageMetadata(user_selected_images[i], filename, size, img_id, filestatus)
        let image_info = {
          id: img_id,
          name: {
            imageName: filename,
            status: filestatus
          },
          path: filepath
        }
        this.image_info_list.push(image_info)
        // console.log("显示的图片列表：",this.image_info_list)
      }
    },
    //从服务器获取图片展示
    show_image(image_index,is_see_second) {
      //image_index 为当前展示的图片下标
      //this.currentIndex 为鼠标点击后的下标
      //this.hasModified  是否修改过当前标注
      this.is_see_second = is_see_second   // 不然后面识别不到
      this.index = image_index
      let image_status = 3
      if (this.currentIndex !== -1){
        image_status = this.image_info_list[this.currentIndex].name.status
      }
      this.show_remote_image(image_index)
    },
    //展示远程服务器图片
    show_remote_image(image_index) {
      // image_index:图片列表的index
      this.reposition()  //复位图片
      this.currentIndex = image_index
      // 如果是第一次加载，那this.image_index为-1，并且没有保存目录树的必要，因为此时目录树为空
      // console.log("尝试")
      // if (this.image_index !== -1) {
      //   // console.log(this.image_index)
      //   // console.log(this.image_id)
      //   // console.log(this.img_metadata)
      //   this.img_metadata[this.image_id].node_tree = this.node_data // 保存目录树
      // }
      if (this.is_loading_current_image) {
        this.$notify({
          title: '请等当前图片加载完再点击',
          type: 'warning',
          duration: 1500
        })
        return
      }
      const img_id = this.image_info_list[image_index].id //  当前图片的id    新的image_id
      if (!this.img_metadata.hasOwnProperty(img_id)) {
        this.$notify({
          title: '图片出错',
          type: 'warning',
          duration: 1500
        })
        return
      }
      const img_filename = this.img_metadata[img_id].filename
      const local_node_data = this.img_metadata[img_id].node_tree
      const local_is_vetical = this.img_metadata[img_id].isVetical
      const img_reader = new FileReader()
      this.is_loading_current_image = true // 正在加载图片
      const that = this
      img_reader.addEventListener('loadstart', function (e) {
      }, false)
      img_reader.addEventListener('progress', function (e) {
      }, false)
      img_reader.addEventListener('error', function () {
        that.is_loading_current_image = false
      }, false)
      img_reader.addEventListener('abort', function () {
        that.is_loading_current_image = false
      }, false)
      img_reader.addEventListener('load', function () {
        that.current_image = new Image()
        that.current_image.addEventListener('error', function () {
          that.is_loading_current_image = false
        }, false)
        that.current_image.addEventListener('abort', function () {
          that.is_loading_current_image = false
        }, false)
        that.current_image.addEventListener('load', function () {
          // update the current state of application
          that.hasModified = false  //加载新的图片，设置为当前图片未标记过
          that.image_id = img_id // 当前的图片id
          that.image_index = image_index // 当前的图片在img_list中的索引
          that.current_image_filename = img_filename
          that.current_image_loaded = true // 图片加载成功
          that.is_loading_current_image = false // 目前不在加载图片
          that.can_change_degree = false  //不能改变旋转角
          that.click_x0 = 0 // 画框的时候用来记录点
          that.click_y0 = 0
          that.click_x1 = 0
          that.click_y1 = 0
          that.is_user_drawing_region = false
          that.is_window_resized = false
          that.is_user_resizing_region = false
          that.is_user_moving_region = false
          that.is_user_drawing_polygon = false
          that.is_region_selected = false
          that.user_sel_region_id = -1
          that.current_image_width = that.current_image.naturalWidth // 图片真实的宽高
          that.current_image_height = that.current_image.naturalHeight
          // // console.log('that.current_image', that.current_image)
          // console.log('that.current_image_width', that.current_image_width)
          // console.log('that.current_image_height', that.current_image_height)
          // set the size of canvas
          // based on the current dimension of browser window
          const de = document.documentElement
          const canvas_panel_width = de.clientWidth - 230 // 宽度-侧边栏的宽度 页面用于显示图像部分的宽高
          const canvas_panel_height = de.clientHeight - 2 * that.ui_top_panel.offsetHeight// 高度-2倍顶栏
          that.canvas_width = that.current_image_width // 真实图片宽度
          that.canvas_height = that.current_image_height
          if (that.canvas_width > canvas_panel_width) { // 如果原图像的大小>页面用于显示图片区域的大小
            // resize image to match the panel width
            const scale_width = canvas_panel_width / that.current_image.naturalWidth
            that.canvas_width = canvas_panel_width // resize
            that.canvas_height = that.current_image.naturalHeight * scale_width
          }
          if (that.canvas_height > canvas_panel_height) {
            // resize further image if its height is larger than the image panel
            const scale_height = canvas_panel_height / that.canvas_height
            that.canvas_height = canvas_panel_height
            that.canvas_width = that.canvas_width * scale_height
          }
          that.canvas_width = Math.round(that.canvas_width)
          that.canvas_height = Math.round(that.canvas_height)
          that.canvas_scale = that.current_image.naturalWidth / that.canvas_width
          that.canvas_scale_without_zoom = that.canvas_scale // 缩放比例
          that.set_all_canvas_size(that.canvas_width, that.canvas_height) // resize img_region和cav_region

          // we only need to draw the image once in the image_canvas 在image_canvas上画一次原图
          that.img_ctx.clearRect(0, 0, that.canvas_width, that.canvas_height) // 清空一定区域内的像素
          that.img_ctx.drawImage(that.current_image, 0, 0, that.canvas_width, that.canvas_height)

          // 加载目录树，如果本地该图片的目录树不为空，则加载本地
          // 如果本地为空，远程端目录树不为'none'，则加载远程的node_data和is_vetical
          that.max_id = 0 // 每一张图片都有自己的从0开始的id编号，由于可能会删除区域，所以不可能连续，所以要获得最大的id，方便接下来计数
          if (local_node_data.length !== 0) {
            // console.log('加载本地目录树数据')
            that.isVetical = local_is_vetical // 加载本地该图片的isVetical信息
            // console.log('本地的isVetical', that.isVetical)
            that.node_data = local_node_data // 加载本地目录树，由于加载本地，所以本地的region已经存了所有的信息了
            for (let i = 0; i < that.node_data.length; i++) { // 获取该目录树的最大id,便于之后添加新的节点
              that.get_max_id(that.node_data[i])
            }
          } else {
            if (that.remote_node_data !== 'none') {
              that.node_data = that.remote_node_data // 加载远程的目录树信息
              console.log("查看节点信息999999999",that.node_data)
              that.isVetical = that.remote_is_vetical // 加载远程端的is_vetical信息
              // 把远程端的目录树信息写入that.img_metadata[img_id].
              that.remote_regions = []
              console.log("查看节点信息888888888888",that.node_data)
              for (let i = 0; i < that.node_data.length; i++) {
                console.log(i)
                console.log("查看节点信息66666666666666",that.node_data)
                that.load_remote_data(that.node_data[i],0) // 把node_data写入regions
                that.get_max_id(that.node_data[i]) // 获取目录树当前最大id
              }
              console.log("查看节点信息77777777777777777",that.node_data)
              // console.log("把node_data写入regions后的数值")
              // console.log(that.remote_regions);
              that.img_metadata[img_id].node_tree = that.remote_node_data
              // that.img_metadata[img_id].node_tree = that.complete_node_data
              that.img_metadata[img_id].isVetical = that.isVetical
              that.img_metadata[img_id].regions = that.remote_regions  //真实大小的坐标
            } else {
              // console.log('本地和远程该目录树都为空')
              that.node_data = local_node_data
              that.isVetical = local_is_vetical
            }
          }
          that.nid = that.max_id + 1 // 用来计数
          that.load_canvas_regions() // 将img_meta中的regions加载到canvas层面
          that.redraw_reg_canvas()
          that.reg_canvas.focus() // 焦点设置在regcav上，以便画图
        })
        // // console.log('img_reader.result', img_reader.result)
        that.current_image.src = img_reader.result
      }, false)
      new Promise((resolve, reject) => {
        resolve(getImage(that.img_metadata[img_id].fileref.filepath,that.img_metadata[img_id].fileid, this.imageData['taskName'],this.is_see_second))// 请求img的地址
      }).then((res) => {
        // 判断二次识别文件是否存在
        that.second_json_is_exist = res.data.second_json_is_exist
        that.img_metadata[img_id].base64_img_data = res.data.imageBase64
        that.remote_node_data = res.data.node_data // 获取远程的nodedata，如果为'none',则说明远程端没有该文件的标注数据
        // console.log(111)
        // console.log(that.remote_node_data)
        // 给所有已识别的节点加上isOcr = true 的属性
        // that.add_node_data_isocr(that.remote_node_data)
        that.remote_is_vetical = res.data.is_vetical // 获取远程的is_vetical状态
        // console.log(that.img_metadata[img_id].base64_img_data)
        if (that.img_metadata[img_id].base64_img_data === '') {
          // load image from file
          img_reader.readAsDataURL(that.img_metadata[img_id].fileref)
        } else {
          // load image from base64 data or URL
          img_reader.readAsText(new Blob([that.img_metadata[img_id].base64_img_data]))
        }
      })
    },
    get_max_id(n_data) { // 获得目录树的最大id值
      if (n_data['id'] > this.max_id) {
        this.max_id = n_data['id']
      }
      for (let i = 0; i < n_data['children'].length; i++) {
        this.get_max_id(n_data['children'][i])
      }
    },
    // 把node_data写入regions  只在初始化时执行
    load_remote_data(n_data,degree) { // 遍历加载regions
      if (n_data['xy'].length !== 0) {
        // Math.round 取整
        let x = Math.round(n_data['xy'][0]) //实际坐标
        let y = Math.round(n_data['xy'][1])
        let width = Math.round(n_data['xy'][2] - n_data['xy'][0])
        let height = Math.round(n_data['xy'][3] - n_data['xy'][1])
        let isOcr = n_data['isOcr']
        let data = {}
        data['label']
        data['result'] = n_data['result']
        // console.log("识别好的文字result",n_data['result'])
        this.ocrWords.push(n_data['result'])
        // let degree = 0
        if (n_data.hasOwnProperty('degree')) {
          degree = n_data['degree']  //倾斜角(非弧度)，倾斜角不为0的时候，xy的坐标经过倾斜角转换才是真实框的坐标
        } else {
          n_data['degree'] = 0
        }
        let img_region = new ImageRegion()
        img_region.node_id = n_data['id']
        img_region.shape_attributes.set('name', 'rect')
        img_region.shape_attributes.set('degree', degree)  //角度而非弧度
        img_region.shape_attributes.set('x', x)
        img_region.shape_attributes.set('y', y)
        img_region.shape_attributes.set('width', width)
        img_region.shape_attributes.set('height', height)
        img_region.shape_attributes.set('isOcr', isOcr)
        this.remote_regions.push(img_region)
      }
      console.log("4444444444444")
      console.log(n_data)
      // 描绘节点(需判断有无chars)
      if (n_data['chars'].length !== 0) {
        for(let i=0;i<n_data['chars'].length;i++){
          let char = n_data['chars'][i]

          let x = Math.round(char['char_box'][0])
          let y = Math.round(char['char_box'][1])
          let width = Math.round(char['char_box'][2] - char['char_box'][0])
          let height = Math.round(char['char_box'][3] - char['char_box'][1])
          let isOcr = n_data['isOcr']
          // let degree = 0

          let img_region = new ImageRegion()
          img_region.node_id = 'a' + char['char_id']
          img_region.shape_attributes.set('name', 'rect')
          img_region.shape_attributes.set('degree', degree)  //角度而非弧度
          img_region.shape_attributes.set('x', x)
          img_region.shape_attributes.set('y', y)
          img_region.shape_attributes.set('width', width)
          img_region.shape_attributes.set('height', height)
          img_region.shape_attributes.set('isOcr', isOcr)
          this.remote_regions.push(img_region)
        }
      }
      console.log("333333333333333")
      console.log(n_data)
      for (let i = 0; i < n_data['children'].length; i++) {
        this.load_remote_data(n_data['children'][i],degree)
      }
    },
    //键盘移动框
    key_move(move_x, move_y) {
      const current_region = this.img_metadata[this.image_id].regions[this.user_sel_region_id]// 用户选择的区域
      const image_attr = current_region.shape_attributes // 真实的坐标 x/y/w/h
      const canvas_attr = this.canvas_regions[this.user_sel_region_id].shape_attributes // 在canvas中的坐标
      const current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)// 当前选择区域的目录树node信息
      // console.log('当前区域对应的目录树节点的信息：', current_node_info)
      switch (canvas_attr.get('name')) {
        case this.REGION_SHAPE.RECT:
          const xnew = image_attr.get('x') + Math.round(move_x * this.canvas_scale) // 因为move_x是在缩小的级别上进行的，所以要*缩小的倍数才能得到实际的坐标
          const ynew = image_attr.get('y') + Math.round(move_y * this.canvas_scale)
          image_attr.set('x', xnew)
          image_attr.set('y', ynew)
          const past_xy = current_node_info.data.xy
          current_node_info.data.xy = []// 初始化节点的信息
          current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[0])
          current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[1])
          current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[2])
          current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[3])
          this.hasModified = true
          canvas_attr.set('x', Math.round(image_attr.get('x') / this.canvas_scale))
          canvas_attr.set('y', Math.round(image_attr.get('y') / this.canvas_scale))
      }
      this.redraw_reg_canvas()
      this.reg_canvas.focus()
    },
    //修改操作
    complete_mark(is_comfirm) {     // is_comfirm为0 暂存，为1则确认
      if(!this.is_can_upload && !this.hasModified){
        this.$notify({
          title: '当前并未修改',
          type: 'warning',
          duration: 2500
        })
        return
      }
      if(is_comfirm == 1 && this.now_status != "已暂存二次识别结果")
      {
        this.$notify({
          title: '当前修改并未识别',
          type: 'warning',
          duration: 2500
        })
        return
      }
      let message = '是否确定修改？';
      this.$confirm(message, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.submitIndex = this.image_index
        // const image_path = this.image_info_list[this.image_index].path
        saveMarkDataRepate(this.imageData['imagePath'], this.isVetical, this.node_data, is_comfirm, this.imageData['taskId'], this.imageData['image_id']).then((response) => {
          console.log("修改的Nodadata",this.node_data)
          this.resultPath = response.resultPath
          this.submitSuccessNotify()
          this.hasModified = true
        }).catch((error) => {
          this.submitFailureNotify(error)
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消'
        });
      });
    },
    //查看修改
    seeEdit(){
      if(this.second_json_is_exist){
        this.is_can_upload = true
        this.img_metadata[this.image_info_list[0].id].node_tree = []
        this.currentIndex = -1
        this.remote_node_data = 'None'
        this.node_data = []
        this.show_image(0,1)
      }else {
        this.$notify({
          title: '未存在当前图片的二次标注文件',
          type: 'warning',
          duration: 2500
        })
      }

    },
    goBack(){
      this.$router.replace('main/tasklist')
    },
    submitSuccessNotify() {
      this.$notify({
        title: '操作成功',
        type: 'success',
        duration: 2500
      })
    },
    submitFailureNotify(error) {
      this.$notify({
        title: '提交失败' + error,
        type: 'error',
        duration: 2500
      })
    },
    //排版方向
    changeVetical() {
      const img_id = this.image_info_list[this.image_index].id
      this.img_metadata[img_id].isVetical = this.isVetical // 修改排版状态
    },
    // reg_canvas鼠标操作
    mouse_down(e) {
      this.click_x0 = e.offsetX //相对于region_canvas的坐标
      this.click_y0 = e.offsetY
      // console.log('鼠标按下:', this.click_x0, this.click_y0)
      this.region_edge = this.is_on_region_corner(this.click_x0, this.click_y0) //点击到框的四角上
      let region_id = this.is_inside_region(this.click_x0, this.click_y0)
      //如果鼠标按到了已经选中的区域，可以移动或者调整区域大小
      //如果按到了没有选中的区域或者本身没有区域被选中，则判定为在画框
      if (this.is_region_selected) {  //是否已经有区域被选中
        // check if user clicked on the region boundary
        if (this.region_edge[1] > 0) {  //点击到了区域边角
          if (!this.is_user_resizing_region) {  //如果在resize区域的状态为false，那么改为true
            // resize region
            if (this.region_edge[0] !== this.user_sel_region_id) {  //如果当前选的区域不是已选中的图像区域，就修改区域id
              this.user_sel_region_id = this.region_edge[0]
            }
            this.is_user_resizing_region = true
            // this.isDragActive = false //resize的时候不能拖动图片
          }
        } else { //没有点击到角落
          let yes = this.is_inside_this_region(this.click_x0, this.click_y0, this.user_sel_region_id)  //点击到区域内部
          if (yes) {  //点击到之前选择的框的内部，把移动状态改为true
            if (!this.is_user_moving_region) {
              this.is_user_moving_region = true
              // this.isDragActive = false //移动区域的时候不能拖动
              this.region_click_x = this.click_x0
              this.region_click_y = this.click_y0
            }
          }
          if (region_id === -1) {//点击到别的区域，判定为在画框
            // unselect all regions
            this.is_region_selected = false
            this.user_sel_region_id = -1
            this.toggle_all_regions_selection(false)
            if (this.can_draw_region) { //如果可以画框
              // mousedown on outside any region
              this.is_user_drawing_region = true
              // this.isDragActive = false
            } else {
              console.log('没有在目录树上新建节点，不能画框')
            }
          }
        }
      } else {  //如果目前没有区域被选中,则判定为在画框
        if (this.can_draw_region) {
          // console.log('没有区域被选中，判定为正在画框')
          this.is_user_drawing_region = true
          // this.isDragActive = false
        } else {
          // console.log('没有在目录树上新建节点不能画框，由于没有区域被选中，所以可以拖动图片')
        }
      }
      e.preventDefault()
    },
    mouse_up(e) {
      this.click_x1 = e.offsetX
      this.click_y1 = e.offsetY
      // console.log('鼠标抬起', this.click_x1, this.click_y1)
      let click_dx = Math.abs(this.click_x1 - this.click_x0)  //移动的距离
      let click_dy = Math.abs(this.click_y1 - this.click_y0)
      // this.isDragActive = true
      // 如果用户正在移动区域
      if (this.is_user_moving_region) {  //如果正在移动区域,即在有区域被选中的情况下，鼠标点击被选中的区域
        this.is_user_moving_region = false  //鼠标抬起，结束移动
        // console.log('移动框结束')
        this.reg_canvas.style.cursor = 'default'

        let move_x = Math.round(this.click_x1 - this.region_click_x)  //区域移动的距离
        let move_y = Math.round(this.click_y1 - this.region_click_y)

        if (Math.abs(move_x) > this.MOUSE_CLICK_TOL || Math.abs(move_y) > this.MOUSE_CLICK_TOL) {  //移动区域
          // console.log('更新移动后框的坐标')
          const current_region = this.img_metadata[this.image_id].regions[this.user_sel_region_id]//用户选择的区域
          let image_attr = current_region.shape_attributes //真实的坐标
          let canvas_attr = this.canvas_regions[this.user_sel_region_id].shape_attributes //在canvas中的坐标
          let current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)//当前选择区域的目录树node信息
          // console.log('当前区域对应的目录树节点的信息：', current_node_info)
          switch (canvas_attr.get('name')) {
            case this.REGION_SHAPE.RECT:
              let xnew = image_attr.get('x') + Math.round(move_x * this.canvas_scale) //因为move_x是在缩小的级别上进行的，所以要*缩小的倍数才能得到实际的坐标
              let ynew = image_attr.get('y') + Math.round(move_y * this.canvas_scale)
              image_attr.set('x', xnew)
              image_attr.set('y', ynew)
              let past_xy = current_node_info.data.xy
              current_node_info.data.xy = []//初始化节点的信息
              current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[0])
              current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[1])
              current_node_info.data.xy.push(move_x * this.canvas_scale + past_xy[2])
              current_node_info.data.xy.push(move_y * this.canvas_scale + past_xy[3])
              canvas_attr.set('x', Math.round(xnew / this.canvas_scale))
              canvas_attr.set('y', Math.round(ynew / this.canvas_scale))
              this.hasModified = true
              break
          }
        }
        // console.log('更新框信息后重新画框')
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // this.save_current_data_to_browser_cache();
        return
      }

      // 如果用户正在重新调整边框大小
      if (this.is_user_resizing_region) {
        // console.log('结束resize框,更新框的信息')
        // click(x0,y0) to click(x1,y1)
        this.is_user_resizing_region = false
        this.reg_canvas.style.cursor = 'default'
        // update the region
        let region_id = this.region_edge[0]
        const current_region = this.img_metadata[this.image_id].regions[region_id]
        let image_attr = current_region.shape_attributes
        let canvas_attr = this.canvas_regions[region_id].shape_attributes
        let current_node_info = this.$refs['vuetree'].getNode(current_region.node_id)//当前选择区域的目录树node信息
        // console.log('当前区域对应的目录树节点的信息：', current_node_info)
        switch (canvas_attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            if (canvas_attr.get('degree') === 0) {
              let d = [canvas_attr.get('x'), canvas_attr.get('y'), 0, 0]
              d[2] = d[0] + canvas_attr.get('width')  //右下
              d[3] = d[1] + canvas_attr.get('height')
              let mx = this.current_x
              let my = this.current_y
              // let preserve_aspect_ratio = false;
              this.rect_update_corner(this.region_edge[1], d, mx, my) //更新左上右下的点
              this.rect_standarize_coordinates(d) //保证是左上右下
              let w = Math.abs(d[2] - d[0])
              let h = Math.abs(d[3] - d[1])
              image_attr.set('x', Math.round(d[0] * this.canvas_scale))
              image_attr.set('y', Math.round(d[1] * this.canvas_scale))
              image_attr.set('width', Math.round(w * this.canvas_scale))
              image_attr.set('height', Math.round(h * this.canvas_scale))
              current_node_info.data.xy = []  //修改目录树中对应节点的坐标信息
              current_node_info.data.xy.push(Math.round(d[0] * this.canvas_scale))
              current_node_info.data.xy.push(Math.round(d[1] * this.canvas_scale))
              current_node_info.data.xy.push(Math.round(d[2] * this.canvas_scale))
              current_node_info.data.xy.push(Math.round(d[3] * this.canvas_scale))
              canvas_attr.set('x', Math.round(image_attr.get('x') / this.canvas_scale))
              canvas_attr.set('y', Math.round(image_attr.get('y') / this.canvas_scale))
              canvas_attr.set('width', Math.round(image_attr.get('width') / this.canvas_scale))
              canvas_attr.set('height', Math.round(image_attr.get('height') / this.canvas_scale))
              this.hasModified = true
            } else {
              //由于此时框不平行于坐标轴，所以要将当前框和鼠标位置映射到和框平行的坐标系中
              //等价于将当前框和鼠标位置的坐标绕原点旋转-degree度，在这个坐标系中将框做resize操作
              //之后再将resize后的坐标再旋转degree度转化为原坐标系的坐标
              let x = canvas_attr.get('x')  //resize的框的坐标
              let y = canvas_attr.get('y')
              let width = canvas_attr.get('width')
              let height = canvas_attr.get('height')
              let degree = canvas_attr.get('degree')
              let c_x = x + width / 2
              let c_y = y + height / 2
              //绕矩阵中心旋转degree度，得到真实的框的左上坐标
              let real_x = Math.round((x - c_x) * Math.cos(degree * (Math.PI / 180)) - (y - c_y) * Math.sin(degree * (Math.PI / 180)) + c_x)
              let real_y = Math.round((x - c_x) * Math.sin(degree * (Math.PI / 180)) + (y - c_y) * Math.cos(degree * (Math.PI / 180)) + c_y)
              //左上角绕原点旋转-degree度
              let x1 = Math.round(real_x * Math.cos(-degree * (Math.PI / 180)) - real_y * Math.sin(-degree * (Math.PI / 180)))
              let y1 = Math.round(real_x * Math.sin(-degree * (Math.PI / 180)) + real_y * Math.cos(-degree * (Math.PI / 180)))
              let d = [x1, y1, x1 + width, y1 + height]  //这个矩形在平行于其边的坐标轴的左上右下坐标
              let mx = this.current_x
              let my = this.current_y
              mx = Math.round(mx * Math.cos(-degree * (Math.PI / 180)) - my * Math.sin(-degree * (Math.PI / 180)))
              my = Math.round(mx * Math.sin(-degree * (Math.PI / 180)) + my * Math.cos(-degree * (Math.PI / 180)))
              this.rect_update_corner(this.region_edge[1], d, mx, my) //更新左上右下的点
              this.rect_standarize_coordinates(d) //保证是左上右下
              let w = Math.abs(d[2] - d[0])
              let h = Math.abs(d[3] - d[1])
              let t = this.compulte_new_xy(d[0], d[1], w, h, degree, 0, 0) //转化为原坐标系
              //旋转左上角点坐标，绕矩形中心旋转-degree度,转化为旋转前的矩阵左上角坐标
              c_x = (t.new_x[0] + t.new_x[2]) / 2
              c_y = (t.new_y[0] + t.new_y[2]) / 2
              x1 = Math.round((t.new_x[0] - c_x) * Math.cos(-degree * (Math.PI / 180)) - (t.new_y[0] - c_y) * Math.sin(-degree * (Math.PI / 180)) + c_x)
              y1 = Math.round((t.new_x[0] - c_x) * Math.sin(-degree * (Math.PI / 180)) + (t.new_y[0] - c_y) * Math.cos(-degree * (Math.PI / 180)) + c_y)
              d = [x1, y1, x1 + w, y1 + h]
              image_attr.set('x', Math.round(d[0] * this.canvas_scale))
              image_attr.set('y', Math.round(d[1] * this.canvas_scale))
              image_attr.set('width', Math.round(w * this.canvas_scale))
              image_attr.set('height', Math.round(h * this.canvas_scale))
              canvas_attr.set('x', d[0])
              canvas_attr.set('y', d[1])
              canvas_attr.set('width', w)
              canvas_attr.set('height', h)
              current_node_info.data.xy = []  //修改目录树中对应节点的坐标信息
              current_node_info.data.xy.push(Math.round(d[0] * this.canvas_scale))
              current_node_info.data.xy.push(Math.round(d[1] * this.canvas_scale))
              current_node_info.data.xy.push(Math.round(d[2] * this.canvas_scale))
              current_node_info.data.xy.push(Math.round(d[3] * this.canvas_scale))
              this.hasModified = true
            }
            break
        }
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        // this.save_current_data_to_browser_cache();
        return
      }

      // denotes a single click (= mouse down + mouse up)单击一个区域，即选中,记录选中区域的id，并且将对应的isselect标记为true
      if (click_dx < this.MOUSE_CLICK_TOL || click_dy < this.MOUSE_CLICK_TOL) {
        // console.log('鼠标按下移动距离过短，判定为单击')
        let region_id = this.is_inside_region(this.click_x0, this.click_y0)
        if (region_id >= 0) {
          // first click selects region
          // console.log('选中框id：', region_id)
          this.user_sel_region_id = region_id
          this.is_region_selected = true
          this.is_user_moving_region = false
          this.is_user_drawing_region = false
          this.can_draw_region = false
          this.can_change_degree = true  //可以改变角度
          this.num_degree = this.canvas_regions[region_id].shape_attributes.get('degree')  //读取角度
          //将目录树的节点设置为高亮状态
          let select_node_id = this.canvas_regions[region_id].node_id
          // console.log('选中框的region_id：', select_node_id)
          this.$refs['vuetree'].setCurrentKey()
          this.$refs['vuetree'].setCurrentKey(select_node_id)
          let node = this.$refs['vuetree'].getNode(select_node_id)
          if (node.level !== 1){
            this.selectCamera(select_node_id)
          }
          // this.selectCamera(select_node_id)
          // de-select all other regions if the user has not pressed Shift
          if (!e.shiftKey) {
            this.toggle_all_regions_selection(false)
          }
          this.set_region_select_state(region_id, true)
          //show_message('Click and drag to move or resize the selected region');
        } else {
          console.log('没有框被选中,取消所有框的选择状态')
          this.is_region_selected = false
          this.use_sel_region_id = -1
          this.can_change_degree = false
          this.$refs['vuetree'].setCurrentKey()  //清空目录树的选中状态
          this.toggle_all_regions_selection(false)
          if (this.is_user_drawing_region) {  //如果没有区域被选中，鼠标按下移动的距离又很小，则全部设置为未选中
            // clear all region selection
            this.is_user_drawing_region = false
          }
        }
        // console.log('取消画框')
        this.redraw_reg_canvas()
        this.reg_canvas.focus()
        return
      }
      // 如果用户画框结束
      if (this.is_user_drawing_region) {
        this.is_user_drawing_region = false
        let current_node = {}
        if (!this.isDrawOther){
          let num_label = this.count_label_num(this.current_parent_node.data, this.current_label)
          current_node = {
            id: this.nid++,
            label: this.current_label,
            label_idx: num_label + 1,
            need_detect: this.current_need_detect,
            degree: 0,  //旋转角 非弧度
            xy: [],  //旋转前框的左上右下坐标
            children: [],
            isOcr: false
            // 哈哈哈哈
          }
        }
        else {
          current_node = this.$refs['vuetree'].getNode(this.current_other_node_id).data

        }
        // this.can_draw_region = false //禁止画框，需要在目录树上新建节点才可以画框
        let region_x0, region_y0, region_x1, region_y1
        // ensure this (x0,y0) is top-left and (x1,y1) is bottom-right
        if (this.click_x0 < this.click_x1) {
          region_x0 = this.click_x0
          region_x1 = this.click_x1
        } else {
          region_x0 = this.click_x1
          region_x1 = this.click_x0
        }
        if (this.click_y0 < this.click_y1) {
          region_y0 = this.click_y0
          region_y1 = this.click_y1
        } else {
          region_y0 = this.click_y1
          region_y1 = this.click_y0
        }

        let original_img_region = new ImageRegion()  //新建一个矩形区域，实际大小
        let canvas_img_region = new ImageRegion()  //画布大小
        let region_dx = Math.abs(region_x1 - region_x0) //区域的大小
        let region_dy = Math.abs(region_y1 - region_y0)

        // newly drawn region is automatically selected
        this.toggle_all_regions_selection(false)
        original_img_region.is_user_selected = true
        canvas_img_region.is_user_selected = true
        original_img_region.node_id = current_node.id //记录node_id
        canvas_img_region.node_id = current_node.id
        this.is_region_selected = true
        this.user_sel_region_id = this.canvas_regions.length // new region's id

        if (region_dx > this.REGION_MIN_DIM || region_dy > this.REGION_MIN_DIM) { // avoid regions with 0 dim
          switch (this.current_shape) {
            case this.REGION_SHAPE.RECT:
              let x = Math.round(region_x0 * this.canvas_scale) //实际坐标
              let y = Math.round(region_y0 * this.canvas_scale)
              let width = Math.round(region_dx * this.canvas_scale)
              let height = Math.round(region_dy * this.canvas_scale)
              original_img_region.shape_attributes.set('name', 'rect')
              original_img_region.shape_attributes.set('degree', 0)
              original_img_region.shape_attributes.set('x', x)
              original_img_region.shape_attributes.set('y', y)
              original_img_region.shape_attributes.set('width', width)
              original_img_region.shape_attributes.set('height', height)
              current_node['xy'] = []
              current_node['xy'].push(region_x0 * this.canvas_scale)
              current_node['xy'].push(region_y0 * this.canvas_scale)
              current_node['xy'].push(region_x1 * this.canvas_scale)
              current_node['xy'].push(region_y1 * this.canvas_scale)
              canvas_img_region.shape_attributes.set('name', 'rect')
              canvas_img_region.shape_attributes.set('degree', 0)
              canvas_img_region.shape_attributes.set('x', Math.round(x / this.canvas_scale))
              canvas_img_region.shape_attributes.set('y', Math.round(y / this.canvas_scale))
              canvas_img_region.shape_attributes.set('width', Math.round(width / this.canvas_scale))
              canvas_img_region.shape_attributes.set('height', Math.round(height / this.canvas_scale))
              // 将新加的节点写入region中
              canvas_img_region.shape_attributes.set('isOcr', false)
              // console.log(this.current_node)
              // console.log(this.current_parent_node)
              if (!this.isDrawOther){
                this.current_parent_node.data.children.push(current_node)  //data绑定了node_data，data发生改变，node_data也发生改变
              }
              this.hasModified = true
              this.can_change_degree = true  //可以改变角度
              this.num_degree = 0  //设置框的默认度数
              // setTimeout(() => {
              //   this.$refs.treeRef.scrollTop = this.$refs.treeRef.scrollHeight
              // }, 100)
              this.img_metadata[this.image_id].regions.push(original_img_region)
              this.canvas_regions.push(canvas_img_region)
              setTimeout(() => {
                this.$refs['vuetree'].setCurrentKey()
                this.$refs['vuetree'].setCurrentKey(current_node.id)
                if (!this.isDrawOther){ //目录树定位到新节点
                  this.selectCamera(current_node.id)
                }
                if (this.isDrawOther){
                  this.isDrawOther = false;
                  this.can_draw_region = false;
                }
                }, 100)
              break
          }
        } else {
          // console.log('不能添加这么小的框!')
        }
        this.redraw_reg_canvas()  //region全部重画
        this.reg_canvas.focus()
        // this.save_current_data_to_browser_cache()
      }

    },
    //标完框之后
    selectCamera(select_node_id) {
      // console.log("标完框之后")
      //这次选中的节点
      let currentNode = this.$refs.vuetree.getNode(select_node_id)
      console.log("currentNode",currentNode)
      let openNode = currentNode
      let sum = 0
      while (openNode.parent !== null) {
        openNode.parent.expanded = true
        openNode = openNode.parent
      }
      //同级
      let all = 0

      let count1 = currentNode.data.label_idx
      // console.log("同级", count1)

      if (currentNode.parent.parent.parent === null) {

      } else {
        currentNode = currentNode.parent
        all = all + count1
      }

      let num = 0
      let num1 = 0
      let label = currentNode.parent.data.label
      let index = currentNode.parent.data.label_idx
      // console.log(label,index)

      let Node = currentNode.parent.parent
      // console.log("第二级")
      // console.log("最顶级",Node)
      let flag = 0
      let beforeCount = 0
      let currentCount = 0
      for (let i = 0; i < Node.childNodes.length; i++) {

        if (Node.childNodes[i].data.label === label && Node.childNodes[i].data.label_idx === index) {
          beforeCount = beforeCount + flag
          // console.log("beforeCount",beforeCount)
          let label1 = currentNode.data.label
          let index1 = currentNode.data.label_idx
          let Node3 = Node.childNodes[i]
          for (let i = 0; i < Node3.childNodes.length; i++) {
            if (Node3.childNodes[i].data.label === label1 && Node3.childNodes[i].data.label_idx === index1) {
              currentCount = currentCount + i
              // console.log("currentCount",currentCount)
              break;
            } else {
              let Node1 = Node3.childNodes[i]
              // console.log("222Node1",Node1)
              if (Node1.expanded === false) {
              } else {
                let sum = 0
                for (let i = 0; i < Node1.childNodes.length; i++) {
                  let Node2 = Node1.childNodes[i]
                  if (Node2.expanded === true) {
                    sum = sum + Node2.childNodes.length + 1
                    // console.log("2if",sum)
                  } else {
                    sum = sum + 1
                    // console.log("2else",sum)
                  }
                }
                num1 = num1 + sum
                // console.log("2sum",sum)
              }
              currentCount = num1
              // console.log("2num",num1)
            }
          }
          break;
        } else {

          let Node1 = Node.childNodes[i]
          if (Node1.expanded === false) {
            num = num + 1
          } else {
            let sum = 0
            for (let i = 0; i < Node1.childNodes.length; i++) {
              let Node2 = Node1.childNodes[i]
              if (Node2.expanded === true) {
                sum = sum + Node2.childNodes.length + 1
                console.log("Node2 sum", sum)
              } else {
                sum = sum + 1
                console.log("Node2 sum", sum)
              }
              console.log("else 内", sum)
            }
            num = num + sum
          }
          beforeCount = num
          console.log("num", num)


          // console.log("Node1",Node1)
        }
        flag = i + 1
        // console.log("index1",flag)
      }
      all = all + beforeCount + currentCount + 1
      // console.log("all",all)
      let dom = document.querySelector("#Tree")
      let dom1 = document.querySelector("#Tree1")
      //一个节点的高度是26px,这个值能否从对象中获取，等我把这个功能做好再考虑吧
      let nodeHight = 26
      // dom1.style.height = (all * nodeHight) + "px"
      // 13是因为，div高度为700像素，nodeHight*27=702，略超过700，
      // 又因为，div高度是700像素，要使被选中的节点显示在div可视区域的中间，
      // 所以就要将27折半，后一半节点要参与滚动条的位移
      // 计算位移距离时，减350的原因也是一样，要使被选中的节点显示在div可视区域的中间，就要减去div高度的一半
      if (9 < all) {
        dom.scrollTo(0, (all * nodeHight) - 100)
      } else {
        dom.scrollTo(0, 0)
      }
    },
    mouse_move(e) {
      if (!this.current_image_loaded) {
        // console.log('还在加载图片')
        return
      }
      this.current_x = e.offsetX
      this.current_y = e.offsetY
      // // console.log('mousemove:', this.current_x, this.current_y)
      if (this.is_region_selected) { //调整鼠标指针
        // // console.log('有区域被选中')
        if (!this.is_user_resizing_region) { //如果不在resize边框
          // check if user moved mouse cursor to region boundary
          // which indicates an intention to resize the reigon

          this.region_edge = this.is_on_region_corner(this.current_x, this.current_y)

          if (this.region_edge[0] === this.user_sel_region_id) {
            // console.log('鼠标移动到被选中的边框角落,鼠标变化为特定的形状')
            switch (this.region_edge[1]) {
              // rect
              case 1: // top-left corner of rect
              case 3: // bottom-right corner of rect
                this.reg_canvas.style.cursor = 'nwse-resize' //1-3方向的箭头
                break
              case 2: // top-right corner of rect
              case 4: // bottom-left corner of rect
                this.reg_canvas.style.cursor = 'nesw-resize'//2-4
                break
              default:
                this.reg_canvas.style.cursor = 'default' //指针
            }
          } else {
            let yes = this.is_inside_this_region(this.current_x,
              this.current_y,
              this.user_sel_region_id)  //如果鼠标移动到选中的区域内部
            if (yes) {
              this.reg_canvas.style.cursor = 'move'
            } else {
              if (this.isDragActive === false)
                this.reg_canvas.style.cursor = 'default'
              else
                this.reg_canvas.style.cursor = 'pointer'
            }
          }
        }
      }

      if (this.is_user_drawing_region) {  //如果正在画框
        // console.log('正在画框')
        // draw region as the user drags the mouse cousor
        if (this.canvas_regions.length) {
          this.redraw_reg_canvas() // 去除中间框，只画已有的框 clear old intermediate rectangle
        } else {
          // first region being drawn, just clear the full region canvas
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
        }

        let region_x0, region_y0  //左上角

        if (this.click_x0 < this.current_x) {
          if (this.click_y0 < this.current_y) {
            region_x0 = this.click_x0
            region_y0 = this.click_y0
          } else {
            region_x0 = this.click_x0
            region_y0 = this.current_y
          }
        } else {
          if (this.click_y0 < this.current_y) {
            region_x0 = this.current_x
            region_y0 = this.click_y0
          } else {
            region_x0 = this.current_x
            region_y0 = this.current_y
          }
        }
        let dx = Math.round(Math.abs(this.current_x - this.click_x0))
        let dy = Math.round(Math.abs(this.current_y - this.click_y0))

        switch (this.current_shape) {
          case this.REGION_SHAPE.RECT:
            this.draw_rect_region(region_x0, region_y0, dx, dy, 0, false)
            break
        }
        this.reg_canvas.focus()
      }

      if (this.is_user_resizing_region) { //如果正在调整边框
        // user has clicked mouse on bounding box edge and is now moving it
        // draw region as the user drags the mouse cousor
        if (this.canvas_regions.length) {
          this.redraw_reg_canvas() // clear old intermediate rectangle
        } else {
          // first region being drawn, just clear the full region canvas
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
        }

        let region_id = this.region_edge[0]
        let canvas_attr = this.canvas_regions[region_id].shape_attributes
        switch (canvas_attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            // original rectangle
            if (canvas_attr.get('degree') === 0) {
              let d = [canvas_attr.get('x'), canvas_attr.get('y'), 0, 0]
              d[2] = d[0] + canvas_attr.get('width')  //右下坐标
              d[3] = d[1] + canvas_attr.get('height')
              let mx = this.current_x  //目前鼠标的位置
              let my = this.current_y
              //this.region_edge[1]正在哪个角resize
              this.rect_update_corner(this.region_edge[1], d, mx, my) //可能会使左上右下坐标顺序发生变化
              this.rect_standarize_coordinates(d)  //防止左上右下坐标顺序发生变化
              let w = Math.abs(d[2] - d[0])
              let h = Math.abs(d[3] - d[1])
              this.draw_rect_region(d[0], d[1], w, h, 0, true)
              break
            } else {
              let x = canvas_attr.get('x')
              let y = canvas_attr.get('y')
              let width = canvas_attr.get('width')
              let height = canvas_attr.get('height')
              let degree = canvas_attr.get('degree')
              let c_x = x + width / 2
              let c_y = y + height / 2
              //绕矩阵中心旋转degree度，得到真实的框的左上坐标
              let real_x = Math.round((x - c_x) * Math.cos(degree * (Math.PI / 180)) - (y - c_y) * Math.sin(degree * (Math.PI / 180)) + c_x)
              let real_y = Math.round((x - c_x) * Math.sin(degree * (Math.PI / 180)) + (y - c_y) * Math.cos(degree * (Math.PI / 180)) + c_y)
              //左上角绕原点旋转-degree度
              let x1 = Math.round(real_x * Math.cos(-degree * (Math.PI / 180)) - real_y * Math.sin(-degree * (Math.PI / 180)))
              let y1 = Math.round(real_x * Math.sin(-degree * (Math.PI / 180)) + real_y * Math.cos(-degree * (Math.PI / 180)))
              let d = [x1, y1, x1 + width, y1 + height]  //这个矩形在平行于其边的坐标轴的左上右下坐标
              let mx = this.current_x
              let my = this.current_y
              mx = Math.round(mx * Math.cos(-degree * (Math.PI / 180)) - my * Math.sin(-degree * (Math.PI / 180)))
              my = Math.round(mx * Math.sin(-degree * (Math.PI / 180)) + my * Math.cos(-degree * (Math.PI / 180)))
              this.rect_update_corner(this.region_edge[1], d, mx, my) //更新左上右下的点
              this.rect_standarize_coordinates(d) //保证是左上右下
              let w = Math.abs(d[2] - d[0])
              let h = Math.abs(d[3] - d[1])
              let t = this.compulte_new_xy(d[0], d[1], w, h, degree, 0, 0) //转化为原坐标系
              //画出该矩形
              this.reg_ctx.beginPath()
              this.reg_ctx.moveTo(t.new_x[0], t.new_y[0])
              this.reg_ctx.lineTo(t.new_x[1], t.new_y[1])
              this.reg_ctx.lineTo(t.new_x[2], t.new_y[2])
              this.reg_ctx.lineTo(t.new_x[3], t.new_y[3])
              this.reg_ctx.closePath()//闭环,从当前点到开始点的路径
              this.reg_ctx.strokeStyle = this.THEME_SEL_REGION_FILL_BOUNDARY_COLOR
              this.reg_ctx.lineWidth = this.THEME_REGION_BOUNDARY_WIDTH / 2
              this.reg_ctx.stroke() //绘制出通过 moveTo() 和 lineTo() 方法定义的路径
              this.reg_ctx.fillStyle = this.THEME_SEL_REGION_FILL_COLOR
              this.reg_ctx.globalAlpha = this.THEME_SEL_REGION_OPACITY //透明度
              this.reg_ctx.fill()
              this.reg_ctx.globalAlpha = 1.0  //不透明
              //画边角四个点
              this.draw_control_point(t.new_x[0], t.new_y[0])
              this.draw_control_point(t.new_x[1], t.new_y[1])
              this.draw_control_point(t.new_x[2], t.new_y[2])
              this.draw_control_point(t.new_x[3], t.new_y[3])
              //
              // //旋转左上角点坐标，绕矩形中心旋转-degree度，旋转成平行与坐标轴的
              // let c_x = (t.new_x[0]+t.new_x[2])/2
              // let c_y = (t.new_y[0]+t.new_y[2])/2
              // let x1 = Math.round((t.new_x[0]-c_x)*Math.cos(-degree*(Math.PI/180))-(t.new_y[0]-c_y)*Math.sin(-degree*(Math.PI/180))+c_x)
              // let y1 = Math.round((t.new_x[0]-c_x)*Math.sin(-degree*(Math.PI/180))+(t.new_y[0]-c_y)*Math.cos(-degree*(Math.PI/180))+c_y)
              // this.draw_rect_region(x1, y1, w, h, degree,true)
            }
            break
        }
        this.reg_canvas.focus()
      }

      if (this.is_user_moving_region) {
        // console.log('正在移动区域')
        // draw region as the user drags the mouse cousor
        if (this.canvas_regions.length) {
          this.redraw_reg_canvas() // clear old intermediate rectangle
        } else {
          // first region being drawn, just clear the full region canvas
          this.reg_ctx.clearRect(0, 0, this.reg_canvas.width, this.reg_canvas.height)
        }
        let move_x = (this.current_x - this.region_click_x)
        let move_y = (this.current_y - this.region_click_y)
        let attr = this.canvas_regions[this.user_sel_region_id].shape_attributes

        switch (attr.get('name')) {
          case this.REGION_SHAPE.RECT:
            this.draw_rect_region(attr.get('x') + move_x,
              attr.get('y') + move_y,
              attr.get('width'),
              attr.get('height'),
              attr.get('degree'),
              true)
            break
        }
        this.reg_canvas.focus()
      }
    },
    mouse_over() {
      // change the mouse cursor icon
      // // console.log('鼠标重新移入画布，重画region')
      this.redraw_reg_canvas()
      this.reg_canvas.focus()
    },

  }
}

</script>

<style scoped>
body {
  min-width: 800px;
  padding: 0;
  margin: 0;
  font-family: "Microsoft YaHei";
}

body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, table, th, td {
  margin: 0;
  padding: 0;
}

.top_panel {
  position: fixed;
  display: block;
  font-size: medium;
  background-color: #42b983;
  color: whitesmoke;
  z-index: 10;
  margin: 0;
  padding: 0;
  width: 100%;
}

.navbar {
  display: right;
}

.navbar ul {
  display: inline;
  list-style-type: none;
  overflow: hidden;
}

.navbar li {
  float: left;
}

.navbar li a, .drop_menu_item {
  display: inline-block;
  color: whitesmoke;
  padding: 0.65em 1.2em;
  text-decoration: none;
}

.navbar li a:hover, .dropdown:hover {
  background-color: #42b983;
  cursor: pointer;
}

.navbar li.dropdown {
  display: inline-block;
}

.navbar .dropdown-content {
  display: none;
  position: absolute;
  background-color: #42b983;
  min-width: 120px;
  border: 1px solid #ffffff;
  font-size: small;
}

.navbar .dropdown-content a {
  color: whitesmoke;
  padding: 0.4em 0.6em;
  text-decoration: none;
  display: block;
  text-align: left;
  background-color: #42b983;
  float: none;
}

.navbar .dropdown-content a:hover {
  background-color: #FFC000;
  color: whitesmoke;
}

.navbar .dropdown:hover .dropdown-content {
  display: block;
}

.toolbar {
  display: inline-block;
  color: white;
  vertical-align: top;
}

.toolbar ul {
  display: inline;
  list-style-type: none;
  overflow: hidden;
}

.toolbar li {
  font-size: medium;
  float: left;
  padding: 0.65em 0.3em;
  color: whitesmoke;
}

.toolbar li:hover {
  background-color: #FFC000;
  color: black;
  cursor: pointer;
}

#fileinfo {
  font-size: small;
  padding: 1.2em 0.8em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Middle panel: containing #image_panel, #leftsidebar */
.middle_panel {
  position: relative;
  display: table;
  table-layout: fixed;
  width: 100%;
  z-index: 1;
  padding: 0;
  top: 3.5em;
  /*padding-top: 1.0125em;  ensures the mouse event (x,y) coordinates are integer */
}

#leftsidebar {
  display: table-cell;
  width: 250px;
  z-index: 10;
  vertical-align: top;
}

#display_area {
  display: table-cell;
  width: 100%;
  z-index: 1;
  margin: 0;
  padding-left: 1em;
  vertical-align: top;
}

#canvas_panel {
  position: relative;
  margin: 0;
  padding: 0;
}

#leftsidebar_collapse_panel {
  display: table-cell;
  position: relative;
  width: 10px;
  z-index: 1;
  vertical-align: top;
  font-size: small;
}

#leftsidebar_collapse_button {
  background-color: #42b983;
  width: 10px;
  height: 25px;
  color: whitesmoke;
  padding: 0.2em;
  border-radius: 0px 5px 5px 0px;
  font-size: large;
}

#leftsidebar_collapse_button:hover {
  color: white;
  cursor: pointer;
}

/* Left sidebar accordion */
button.leftsidebar_accordion {
  font-size: large;
  background-color: #f2f2f2;
  cursor: pointer;
  padding: 0.5em 0.5em;
  width: 100%;
  text-align: left;
  border: 0;
  outline: none;
}

button.leftsidebar_accordion:focus {
  outline: none;
}

button.leftsidebar_accordion.active, button.leftsidebar_accordion:hover {
  background-color: #e6e6e6;
}

button.leftsidebar_accordion:after {
  content: '\02795';
  color: #4d4d4d;
  float: right;
}

button.leftsidebar_accordion.active:after {
  content: '\2796';
}

.leftsidebar_accordion_panel {
  display: none;
  padding-top: 0;
  padding-left: 0.5em;
  font-size: small;
  border-right: 2px solid #f2f2f2;
  border-bottom: 2px solid #f2f2f2;
}

.leftsidebar_accordion_panel.show {
  display: block;
}

/* Region shape selection panel inside leftsidebar */
ul.region_shape {
  font-size: xx-large;
  list-style-type: none;
  overflow: hidden;
  padding: 0.4em 0;
  margin: 0;
}

ul.region_shape li {
  float: left;
  padding: 0 0.2em;
  fill: #ffffff;
  stroke: #000000;
}

ul.region_shape li:hover {
  cursor: pointer;
  fill: #ffffff;
  stroke: #ff0000;
}

ul.region_shape .selected {
  fill: #ffffff;
  stroke: #ff0000;
}

/* Loaded image list shown in leftsidebar panel */
#img_list_panel {
  display: none;
  height: 0;
  font-size: small;
  overflow: scroll;
}

#img_list_panel ul {
  position: relative;
  line-height: 1.3em;
  padding-left: 0;
  list-style-type: none;
}

#img_list_panel li {
  white-space: nowrap;
}

#img_list_panel li:hover {
  background-color: #cccccc;
  color: #000000;
  cursor: pointer;
}

#message_panel {
  position: fixed;
  left: 0;
  bottom: 0px;
  line-height: 3em;
  width: 100%;
  background-color: #00a9cf;
  color: black;
  font-size: small;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 1000;
}

/*#invisible_file_input {*/
/*  width: 0.1px;*/
/*  height: 0.1px;*/
/*  opacity: 0;*/
/*  overflow: hidden;*/
/*  position: absolute;*/
/*  z-index: -1;*/
/*}*/

.text_panel {
  display: none;
  margin: auto;
  font-size: medium;
  line-height: 1.3em;
  margin: 0;
  max-width: 700px;
}

.text_panel li {
  margin: 1em 0;
  text-align: left;
}

.text_panel p {
  text-align: left;
}

.action_text_link {
  background-color: #aaeeff;
  color: #000000;
}

.action_text_link:hover {
  cursor: pointer;
}

.svg_button:hover {
  cursor: pointer;
}

.tool_button {
  color: blue;
  cursor: pointer;
}

.tool_button:hover {
  color: red;
}

/* region and file attributes input panel (spreadsheet like) */
#attributes_panel {
  display: none;
  position: fixed;
  bottom: 0;
  z-index: 10;
  width: 100%;
  max-height: 30%;
  overflow: auto;
  background-color: #ffffff;
  border-top: 4px solid #000000;
  padding: 0em 0em;
  padding-bottom: 2em;
  font-size: small;
}

#attributes_panel table {
  border-collapse: collapse;
  table-layout: fixed;
  margin: 1em;
  margin-bottom: 2em;
}

#attributes_panel td {
  border: 1px solid #999999;
  padding: 1em 1em;
  margin: 0;
  height: 1em;
  white-space: nowrap;
  vertical-align: top;
}

#attributes_panel tr:first-child td, #attributes_panel td:first-child {
  padding: 1em 1em;
  text-align: center;
}

#attributes_panel input {
  border: none;
  padding: 0;
  margin: 0;
  display: table-cell;
  height: 1.3em;
  font-size: small;
  background-color: #ffffff;
  vertical-align: top;
}

#attributes_panel input:hover {
  background-color: #e6e6e6;
}

#attributes_panel input:focus {
  background-color: #e6e6e6;
}

#attributes_panel input:not(:focus) {
  text-align: center;
}

#attributes_panel textarea {
  border: none;
  padding: 0;
  margin: 0;
  display: table-cell;
  font-size: small;
  background-color: #ffffff;
}

#attributes_panel textarea:hover {
  background-color: #e6e6e6;
}

#attributes_panel textarea:focus {
  background-color: #e6e6e6;
}

#attributes_panel_toolbar {
  display: block;
  height: 30px;
  width: 100%;
  position: relative;
  padding: 0;
  margin: 0;
}

.attributes_panel_button {
  width: 10px;
  color: black;
  font-size: x-large;
  margin-left: 0.5em;
  padding: 0;
}

.attributes_panel_button:hover {
  color: red;
  cursor: pointer;
}

/* layers of canvas */
#image_panel {
  position: relative;
  display: inline-block;
  margin: auto;
  margin-top: 1em;
}

#image_canvas {
  position: absolute;
  border: 2px solid #d71b1b;
  top: 0px;
  left: 0px;
  z-index: 1;
}

#region_canvas {
  position: absolute;
  top: 0px;
  left: 0px;
  z-index: 2;
}

/* Loading spinbar */
.loading_spinbox {
  display: inline-block;
  border: 0.4em solid #cccccc;
  border-radius: 50%;
  border-top: 0.4em solid #000000;
  -webkit-animation: spin 2s linear infinite;
  animation: spin 2s linear infinite;
}

@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);
  }

  100% {
    -webkit-transform: rotate(360deg);
  }
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.text {
  font-size: 14px;
}

li {
  list-style: none;
}

.item {
  margin-bottom: 18px;
}

.clearfix:before,
.clearfix:after {
  display: table;
  content: "";
}

.clearfix:after {
  clear: both
}

.box-card {
  width: auto;
  /*padding-left: 5px;*/
}

.el-dropdown-link {
  cursor: pointer;
  color: #409EFF;
}

.el-icon-arrow-down {
  font-size: 12px;
}

.demonstration {
  display: block;
  color: #8492a6;
  font-size: 14px;
  margin-bottom: 20px;
}

.custom-class .menu_item__available:hover {
  background: #ffecf2 !important;
  color: #ff4050 !important;
}

.leftSizeBar {
  position: fixed;
}

.box-card {
  height: 100%;
  /*padding: 0;*/
}

.tree_box {
  max-height: 400px;
  overflow: auto;
}

.box {
  max-height: 200px;
  overflow: auto;
}

.explorerBox {
  height: 390px;
  overflow: auto;
}

.el-switch__label {
  position: absolute;
  display: none;
  font-size: 11px !important;
  color: #fff !important;
}

.el-switch__label * {
  font-size: 11px !important;
}

/*打开时文字位置设置*/
.el-switch__label--right {
  z-index: 1;
  right: -10px;
  top: 0.5px;
}

/*关闭时文字位置设置*/
.el-switch__label--left {
  z-index: 1;
  left: 23px;
  top: 0.5px;
}

/*显示文字*/
.el-switch__label.is-active {
  display: block;
}

.el-switch__core {
  width: 45px;
  height: 22px;
  border: 2px solid #DCDFE6;
  border-radius: 13px;
}

.active {
  color: red;
}

.btnClass {
  font-size: 16px;
  margin-right: 30px;
  margin-left: 30px;
}

.mainSizeBar {
  margin-left: 250px;
}

</style>
